Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Can someone point me to a VSCode and Git/VSTS for dummies blog post?My team has no version control whatsoever and this should be an easy thing for me to set up and get brownie points for. I've barely managed to get VSCode set up with a couple plugins for Powershell and VSTS. I tried setting up a Git repository in VSTS and I think I've managed to get VSTS to commit to my local repo but I can't get the changes to sync to VSTS.

Adbot
ADBOT LOVES YOU

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Pay no attention to the man behind the curtain

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

What do you all use for version control? I've been trying to set up Git at work, and either Git is obtuse, I'm dumb, or both.

What I want is a repository that lives on an internal file share with the authoritative versions of those files actually stored there. I want something as close to seamless as possible for an ISE like VSCode (or whatever) to be pointed at that file share (repo, whatver) and natively edit those files with changes silently synced without having to muck around with the command line with every save. Our infrastructure is set up in such a way that scripts need to be ("need to be") locally edited on a variety of machines. Right now we use the ISE and frequently hear "wait a minute, this is the wrong file, I know I fixed this the other day, where is it" and queue the half hour of searching or re-coding.

While testing, I managed to get VSCode doing that with a cloud hosted repo on VSTS, but cloud hosted won't work in production for a variety of reasons. So now I'm trying a bunch of variations of

code:
git init
git clone
git remote add origin
git commit
git pull
and while I can get the remote repo synced locally, I can't figure out why the hell my local changes don't get pushed upstream. I must be missing one or two necessary steps but I dont know what the hell I am doing wrong. Alternatively, SVN seems like its designed more for centralized repositories, but the first time I mentioned it my boss said he didn't want to use it, so I dont know.

Help?

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Jesus gently caress I don't understand any of this. Using VS Code to sync which does a pull and then a push.
code:

Git push origin master
Remote:error:refusing to update checked out branch: refs/head/master
By default, bla bla non bare repository will make the index and work tree inconsistent 
[remote rejected] master - >master (branch is currently checked out

I can use a bare repo as my remote (cloning the repo locally and then committing and pushing to the remote) works. loving finally. But the files all live on my workstation, since it's a bare repo.

OK. Make a bare repo, clone it to another folder on the server. Clone that other folder locally. Pull and push. Same loving error.

What the gently caress.

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

When I do Invoke-VMScript in PowerCLI - which feeds strings of code into a VM - and I need to dynamically update variables, I call the variable #variable and then to a $string.replace(#variable,$variable). For instance:
code:
foreach ($i in $ImportedCSV){
$VMName = $i.Name
$lanIP = $i.IP
[etc]

$Scriptblock = @'
Remove-NetIPAddress [stuff]
New-NetIPAddress - InterfaceIndex $Index -IPAddress "#LanIP" -PrefixLength 24 -DefaultGateway "#LanGW"
Set-DNSClientServerAddress -InterfaceIndex $Index -ServerAddresses #DNS1,#DNS2
Rename-Computer -NewName "#VMName"

'@

$Scriptblock = Scriptblock.Replace("#VMName",$VMName).Replace("#LanIP",$LanIP) [etc]
Invoke-VMScript -vm $VMName [etc]
}
Where those variables are read from an import-CSV that reads a manifest file of all the VMs I am building in that go-around. The beginning of the loop seems overly declaratory, and there's almost certainly a slicker way to do it, but it definitely reads the values again for each loop and then the string.replace object definitely inserts them into my code string each time. I've never seen Call-Script before, but possibly you could implement something like that?

Happiness Commando fucked around with this message at 18:31 on Nov 12, 2018

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

slartibartfast posted:

If you're ever at a conference and bump into a dbatools contributor, buy 'em a beer. :)

Not emptyquoting. Dbatools is loving awesome.

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Work is willing to pay for some training. Before I started this job (and using powershell every day), I tried working my way through the month of lunches book and never finished. I imagine the right move is for me to start it again and finish it this time, and then look at the toolmaking book too.

What do I do after that?

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

AWS Powershell is definitely the bastard offspring. IDK if the rest of the API documentation is as terrible as the Powershell one is, but its frequently wrong. Also much of their getting started documentation says "Here's how to do it in AWS CLI" and then ignores Powershell. Furthermore there's no (official?) API to Powershell lookup table - I've had to click on my best guesses for the cmdlets I want and then read the body text to see what API calls it makes.

Also don't get me started on parameters that are documented as optional but are in fact mandatory and only have one allowed value.

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Pile Of Garbage posted:

Is there any actual evidence, like testing with Measure-Command, to support this?

We used phone timers instead of measure-command, but the end result was that we stopped using += with string arrays at work because of how slow it is.

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

I'm not exactly clear on what's failing for you - when I evaluate $computers[0].'Ip address', I find that a null value doesn't return true. Are you looking to evaluate if each CSV line has an IP address, or the CSV as a whole?
code:

PS C:\Users\Happiness Commando> $computers

Name IP Address
---- ----------
foo            
bar  1.1.1.1   

PS C:\Users\Happiness Commando> if ($computers[0].'IP Address') {"true"}

PS C:\Users\Happiness Commando> if ($computers[1].'IP Address') {"true"}
true
If you want to test the CSV as a whole, you can use Select-Object
code:
if (-not ($computers | Select-Object -Property "ip address")) { Do-Stuff } #I've gotten in trouble with -not precedence before so I use lots of parenthesis
If you want to test that each line item has an IP Address, I don't see why you couldn't enumerate across the whole thing and check for null or whitespace
code:
$computers | % {
    if ([String]::IsNullOrWhiteSpace($_.'ip address')) {
        "no IP"
    }
    else {
        Do-Stuff
    }
}
This zero upvote Stack answer offers a solution to working with XLS files, you would have to validate that it actually works.

I don't know how to do #3, and I would be surprised if there was a reasonable way. My solution would be to preprocess the data so that you have an actual CSV instead of a pseudo-CSV with a separator indicator prepended to a proper CSV - which is what you're doing.

Happiness Commando fucked around with this message at 02:43 on Dec 22, 2020

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

When you put a variable inside double quotes, it expands the variable first, not including the property (basename, in this case). So when you have "$_.basename.aiff" it's outputting the value of $_ and then appending .basename.aiff to the string. If you want to reference object properties in strings, you have to use the "$($variable.property)" interpolation syntax. This should help:

code:
PS C:\temp> $foo = get-item .\testfile.txt
PS C:\temp> $foo


    Directory: C:\temp


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         4/17/2021  12:37 PM              0 testfile.txt


PS C:\temp> $foo.basename
testfile
PS C:\temp> "$foo.basename"
C:\temp\testfile.txt.basename
PS C:\temp> "$($foo.basename).suffix"
testfile.suffix
PS C:\temp>

Happiness Commando fucked around with this message at 19:55 on Apr 17, 2021

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Exit-PsSession exits out of interactive remote sessions - i.e. the result of Enter-PsSession. It doesn't terminate the session, that's what Remove-PsSession does. But it's not clear to me that open sessions are relevant here, since you're using Invoke-Command on a remote target. I have always assumed that invoke-command run against a remote host (edit: rather than through an open session) terminates its own ephemeral session.

How many executions do you get before it starts failing?

Edit: This might be informative

code:
PS C:\WINDOWS\system32> invoke-command -ScriptBlock{hostname}
Slim
PS C:\WINDOWS\system32> get-pssession
PS C:\WINDOWS\system32> invoke-command -ComputerName SOTINY -Credential $cred -ScriptBlock{hostname}
SOTINY
PS C:\WINDOWS\system32> get-pssession
PS C:\WINDOWS\system32>
code:
PS C:\WINDOWS\system32> get-pssession
PS C:\WINDOWS\system32> $sess = new-pssession -computername sotiny -credential $cred
PS C:\WINDOWS\system32> get-pssession

 Id Name            ComputerName    ComputerType    State         ConfigurationName     Availability
 -- ----            ------------    ------------    -----         -----------------     ------------
  5 WinRM5          sotiny          RemoteMachine   Opened        Microsoft.PowerShell     Available


PS C:\WINDOWS\system32> invoke-command -Session $sess -ScriptBlock {hostname}
SOTINY
PS C:\WINDOWS\system32> $sess | remove-pssession
PS C:\WINDOWS\system32> get-pssession
PS C:\WINDOWS\system32>
code:
PS C:\WINDOWS\system32> $sess = new-pssession -computername sotiny -credential $cred
PS C:\WINDOWS\system32> enter-pssession $sess
[sotiny]: PS C:\Users\Happiness Commando\Documents> hostname
SOTINY
[sotiny]: PS C:\Users\Happiness Commando\Documents> exit-pssession
PS C:\WINDOWS\system32> get-pssession

 Id Name            ComputerName    ComputerType    State         ConfigurationName     Availability
 -- ----            ------------    ------------    -----         -----------------     ------------
  6 WinRM6          sotiny          RemoteMachine   Opened        Microsoft.PowerShell     Available


PS C:\WINDOWS\system32> get-pssession |remove-pssession
PS C:\WINDOWS\system32>

Happiness Commando fucked around with this message at 19:50 on Nov 25, 2021

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Have you confirmed that the necessary services on both target and source computers are still up even when it fails (i.e. whatever WinRM services, SQL services, whatever) or looked for interesting time correlated events in the event logs? 5 executions is weird AF, and even if remote Powershell happened over RPC, you wouldn't expect your RPC range to only be 5 ports wide.

Take a packet capture. Bonus points if you can get the capture of the nth execution that fails for the first time and the n-1th execution that immediately precedes the failure.

I'm very curious to find out what the resolution is,.

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Those are the worst/best problem resolutions

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Sounds like you want to do SQL join-like operation:

code:
SELECT * FROM Shareddrives.xlsx INNER JOIN Users.xlsx ON Shareddrives.xlsx.owner1 = Users.xlsx.username
I'd probably use Join-Object after first ingesting the Excel files as CSVs using Import-CSV

Edit: Oh, hmm, IDK how this pattern would work if you have to look at owner1 or owner2. What about something like this? First you populate your variables, or in the case of the output hashtable, initialize it and leave it empty. Then iterate through all the lines of the users file. For each row of the users file, iterate through all the lines of the shared drives file. If the username matches either of the owners, store it in a temp variable and then write it to the output hashtable. When you've gone through every line, dump the output to a csv. This is super hacky (using the % alias of Foreach-Object is bad practice, using Foreach-Object isn't performant, there's probably a more elegant way) but I think it will work as described.
code:
$users = import-csv users.csv
$shareddrives = import-csv shareddrives.csv
$output = @{}

$users | % {
    $username = $_.username
    $shareddrives | % {
        if ($username -eq $_.owner1){
            $owner = $_.owner1
         } 
         if ($username -eq $_.owner2){
            $owner = $_.owner2
         }
         $output.add($_.sharepath, $owner)
    }
     
}
$output | export-csv -path c:\shareddriveowners.csv
"how to approach it" is either breaking down the problem into atomic operations or pattern-matching for a solution you've already found. In this case, I've approached it as:

Import the .xlsx files so you can do stuff with them
Match the username with the owner field
Dump the output somewhere

and "Match the username with the owner field" is approached as

Store the username somewhere
Compare the username to each of the owner fields
If it matches, add it to my list to output at the end
If it doesn't match, keep looking

Happiness Commando fucked around with this message at 05:31 on Mar 2, 2022

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Ooh that's slick

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

incoherent posted:

Hey all, trying to write baby first parameter based script and i'm sure I'm in over my head and it's probably the simplest thing to write ever, but i can't link all the parts together.

The task: To take a parameter given to it from the command line (for example: -dept "shipping") and two different variables (which I'm reading should be an "arrays") list to the command i'm running.

I need to define that "shipping" is $dept and $deptFile and fill in where entered.

(Yes, yes my name is my name. I'm sure there is a better way of articulating this!)

I dont understand what you're asking for when you say "two different variables (which I'm reading should be an "arrays") list to the command i'm running."

At the simplest level, you define a parameter with param ($ParamName). So if you want to do -dept "shipping", you would put at the top of your script param ($dept) and then run it as .\myscript.ps1 -dept "shipping". And then inside the script, the variable $dept stores the string "shipping".

If you want to get more complicated, you can cast the parameters as types (switch, boolean, whatever), make them mandatory or not, set an order, etc. But at their most basic, you just throw them in a variable and call the script using that variable as a flag.

Happiness Commando fucked around with this message at 19:28 on Mar 11, 2022

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

klosterdev posted:

Newbie Powershell question, I'm trying to figure out how to powershell forcing a password reset on next login to specific users in Azure AD, but it looks like the only way to do so it by specifying object ID, and I'd like to do it by selecting userprincipalname. How do I combine

Get-AzureADUser -ObjectId "name@domain.com" | select objectid

with

Set-AzureADUserPassword -ObjectId "ObjectIDGoeshere" -ForceChangePasswordNextLogin 1

Without knowing the behavior of those particular cmdlets, you may be able to just pipe the one to the other. Powershell is frequently good about inferring the way objects fit together. And sometimes infuriating bad.


code:

Get-AzureADUser -ObjectId "name@domain.com"  | Set-AzureADUserPassword -ForceChangePasswordNextLogin 1

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Sure. Use task scheduler to run a powershell script that does those 7 commands. But why can't you just mount those network locations natively?

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Does anyone happen to have an AWS sigv4 signing script to share, or can point out what's wrong here? I need to calculate some credential from some other credential, which involves hashing a bunch of concatenated strings and storing them in byte arrays (I think?). The python code example from documentation works perfectly. The powershell copypasta from the internet ends up with a different final value (is broken) , but it looks like it's accomplishing the same thing. Printing diagnostics mid calculation doesn't help because the HMAC function operates on byte arrays and they are displayed very differently. They're both using utf-8, so I don't think it has to do with string encoding.


Python from https://docs.aws.amazon.com/ses/latest/dg/smtp-credentials.html works perfectly

Python code:

#!/usr/bin/env python3

import hmac
import hashlib
import base64
import argparse

SMTP_REGIONS = [
    "us-east-2",  # US East (Ohio)
    "us-east-1",  # US East (N. Virginia)
    "us-west-2",  # US West (Oregon)
    "ap-south-1",  # Asia Pacific (Mumbai)
    "ap-northeast-2",  # Asia Pacific (Seoul)
    "ap-southeast-1",  # Asia Pacific (Singapore)
    "ap-southeast-2",  # Asia Pacific (Sydney)
    "ap-northeast-1",  # Asia Pacific (Tokyo)
    "ca-central-1",  # Canada (Central)
    "eu-central-1",  # Europe (Frankfurt)
    "eu-west-1",  # Europe (Ireland)
    "eu-west-2",  # Europe (London)
    "eu-south-1",  # Europe (Milan)
    "eu-north-1",  # Europe (Stockholm)
    "sa-east-1",  # South America (Sao Paulo)
    "us-gov-west-1",  # AWS GovCloud (US)
]

# These values are required to calculate the signature. Do not change them.
DATE = "11111111"
SERVICE = "ses"
MESSAGE = "SendRawEmail"
TERMINAL = "aws4_request"
VERSION = 0x04


def sign(key, msg):
    return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()


def calculate_key(secret_access_key, region):
    if region not in SMTP_REGIONS:
        raise ValueError(f"The {region} Region doesn't have an SMTP endpoint.")

    signature = sign(("AWS4" + secret_access_key).encode("utf-8"), DATE)
    signature = sign(signature, region)
    signature = sign(signature, SERVICE)
    signature = sign(signature, TERMINAL)
    signature = sign(signature, MESSAGE)
    signature_and_version = bytes([VERSION]) + signature
    smtp_password = base64.b64encode(signature_and_version)
    return smtp_password.decode("utf-8")


def main():
    parser = argparse.ArgumentParser(
        description="Convert a Secret Access Key to an SMTP password."
    )
    parser.add_argument("secret", help="The Secret Access Key to convert.")
    parser.add_argument(
        "region",
        help="The AWS Region where the SMTP password will be used.",
        choices=SMTP_REGIONS,
    )
    args = parser.parse_args()
    print(calculate_key(args.secret, args.region))


if __name__ == "__main__":
    main()


Powershell copypasta from https://gist.github.com/jacqueskang/96c444ee01e6a4b37300aa49e8097513 provides a credential, the code doesn't error out, but it doesn't work and is different from the python

code:

$key = "${SecretAccessKey}";
$region = "${AWS::Region}";

$date = "11111111";
$service = "ses";
$terminal = "aws4_request";
$message = "SendRawEmail";
$versionInBytes = 0x04;

function HmacSha256($text, $key2) {
    $hmacsha = New-Object System.Security.Cryptography.HMACSHA256
    $hmacsha.key = $key2;
    $hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($text));
}

$signature = [Text.Encoding]::UTF8.GetBytes("AWS4" + $key)
$signature = HmacSha256 "$date" $signature;
$signature = HmacSha256 "$region" $signature;
$signature = HmacSha256 "$service" $signature;
$signature = HmacSha256 "$terminal" $signature;
$signature = HmacSha256 "$message" $signature;
$signatureAndVersion = [System.Byte[]]::CreateInstance([System.Byte], $signature.Length + 1);
$signatureAndVersion[0] = $versionInBytes;
$signature.CopyTo($signatureAndVersion, 1);
$smtpPassword = [Convert]::ToBase64String($signatureAndVersion);

Write-Host $smtpPassword;


Edit:

Wait, using "foo" as my key and us-east-1 as my region results in both outputs being the same. OK I guess I'm going to rubber duck phone post in the edits
BPtBXSjHoMVKYLkS05QmpTxdAWirYy2yB4VgpkK4IhqP

Happiness Commando fucked around with this message at 16:00 on Feb 13, 2024

Adbot
ADBOT LOVES YOU

Happiness Commando
Feb 1, 2002
$$ joy at gunpoint $$

Are you capturing the output of that script, or just that you ran the script?

If the script outputs something, just set a variable to be the called script like so (the script just does get-date)
code:
PS C:\Users\HC> $foo = .\getdate.ps1
PS C:\Users\HC> $foo

Monday, April 15, 2024 1:57:37 PM


PS C:\Users\HC>
Or to log that you run the script, use the transcript (this script just does get-date but dumps it to a file):
code:
PS C:\Users\HC> Start-Transcript -Path .\log.txt
Transcript started, output file is .\log.txt
PS C:\Users\HC> .\getdate.ps1
PS C:\Users\HC> Stop-Transcript
Transcript stopped, output file is C:\Users\HC\log.txt
PS C:\Users\HC> cat .\date.txt

Monday, April 15, 2024 2:03:58 PM


PS C:\Users\HC> cat .\log.txt
**********************
Windows PowerShell transcript start
Start time: 20240415140352
Username: BEEFY\HC
RunAs User: BEEFY\HC
Configuration Name:
Machine: BEEFY (Microsoft Windows NT 10.0.22631.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 36432
PSVersion: 5.1.22621.2506
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.22621.2506
BuildVersion: 10.0.22621.2506
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
Transcript started, output file is .\log.txt
PS C:\Users\HC> .\getdate.ps1
PS C:\Users\HC> Stop-Transcript
**********************
Windows PowerShell transcript end
End time: 20240415140401
**********************
PS C:\Users\HC>
I guess if you're really into the CSV, you could do some string manipulation on the transcript and wrap that all up in a custom function that you load as part of your profile

Happiness Commando fucked around with this message at 21:07 on Apr 15, 2024

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply