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
Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
That was the extra-paranoid retry version but this is sufficient to screw up too:
code:
Start-Sleep -Seconds 300
If(Test-Path C:\vagrant\trampoline\in -eq $false) {
    throw "C:\vagrant\trampoline\in was never created."
}
If I put that in the same script that's starting the task, then my failure rate is something like 75%. If I put it in a separate script, it's historically more like 2% but it suddenly decided to be something like 25%.

I'm fine for nitpicking to work on my PowerShell kung-fu but I also wanted to fix the core of the problem:
  • $trampoline_retries is defined elsewhere. Don't worry about that.
  • They are hard-coded.
  • To be honest about the recursion, I haven't really studied what it's been claiming since the problem resurged so I don't know anything about it's behavior and performance. In the context of what it's doing, it's part of a 2.5-hour regression test so taking two minutes to fart around up-front before failing within 10 minutes isn't a big concern. Point noted nonetheless.
  • The Set-Variable stuff is kind of a cargo-cult reaction to finding variables not sticking in subclauses. I had it happen repeatedly that I'd define a variable outside of scope and then try to assign it in conditionals. None of the conditional assignments were sticking until I used Set-Variable.
  • Write-Verbose is probably what a grown-up should use. I was just trying to get some quick vomit for a QA test. Preferably, I wouldn't need to write anything at all but point noted.

Toast Museum posted:

I hope this doesn't come off as nitpicky; I'm hoping that squaring away some of the tangential stuff will help clarify what's causing the issue at hand.
I can't really say anything because I feel like I'm going to get a custom title some day about the way I piss and moan when people try to X-instead-of-Y on me.

Adbot
ADBOT LOVES YOU

Submarine Sandpaper
May 27, 2007


I'm having some regex issues and the various online calcs are not helping me resolve.

Looking to determine if doing a cleanup is worthwhile and I want to see how much is cleaned up if it is.

Creating the txt with:

$DISMAnalyze = & "Dism.exe" /Online /Cleanup-Image /AnalyzeComponentStore

and $DISMAnalyze is a system.string. Will have an expected output like the below:

code:
....
Component Store (WinSxS) information:

Windows Explorer Reported Size of Component Store : 11.06 GB

Actual Size of Component Store : 10.60 GB

    Shared with Windows : 6.06 GB
    Backups and Disabled Features : 4.48 GB
    Cache and Temporary Data : 55.69 MB

Date of Last Cleanup : 2019-10-30 08:23:50

Number of Reclaimable Packages : 2
Component Store Cleanup Recommended : Yes

The operation completed successfully.
I'm looking to extract the Actual Size of component Store.

Even something simple like
$DismAnalyze.ToString() -match '[0-9]*\.[0-9]*\s\wB'
is giving me a false. For whatever reason I still have to .ToString() it to get a return with -match, whether true or false. Online calcs are saying this should return all instances of *.* GB or *.* MB.

I'm going crazy.

The Fool
Oct 16, 2003


code:
($DISMAnalyze.Split([Environment]::NewLine) | Where {$_ -like "Actual Size of Component Store*"}).Split(":")[1].Trim()
This is how I would do it without regex.

The Fool
Oct 16, 2003


Rocko Bonaparte posted:

I'm fine for nitpicking to work on my PowerShell kung-fu but I also wanted to fix the core of the problem:

Did you have a chance to try the .net method? I'm curious if the behavior is different in your use case or not.

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


Submarine Sandpaper posted:

I'm having some regex issues and the various online calcs are not helping me resolve.

Looking to determine if doing a cleanup is worthwhile and I want to see how much is cleaned up if it is.

Creating the txt with:

$DISMAnalyze = & "Dism.exe" /Online /Cleanup-Image /AnalyzeComponentStore

and $DISMAnalyze is a system.string. Will have an expected output like the below:

code:
....
Component Store (WinSxS) information:

Windows Explorer Reported Size of Component Store : 11.06 GB

Actual Size of Component Store : 10.60 GB

    Shared with Windows : 6.06 GB
    Backups and Disabled Features : 4.48 GB
    Cache and Temporary Data : 55.69 MB

Date of Last Cleanup : 2019-10-30 08:23:50

Number of Reclaimable Packages : 2
Component Store Cleanup Recommended : Yes

The operation completed successfully.
I'm looking to extract the Actual Size of component Store.

Even something simple like
$DismAnalyze.ToString() -match '[0-9]*\.[0-9]*\s\wB'
is giving me a false. For whatever reason I still have to .ToString() it to get a return with -match, whether true or false. Online calcs are saying this should return all instances of *.* GB or *.* MB.

I'm going crazy.

Hey, can you do something more like this:
PowerShell code:
$DISMAnalyze = "Component Store (WinSxS) information:

Windows Explorer Reported Size of Component Store : 11.06 GB

Actual Size of Component Store : 10.60 GB

    Shared with Windows : 6.06 GB
    Backups and Disabled Features : 4.48 GB
    Cache and Temporary Data : 55.69 MB

Date of Last Cleanup : 2019-10-30 08:23:50

Number of Reclaimable Packages : 2
Component Store Cleanup Recommended : Yes

The operation completed successfully."

$DISMAnalyze -match 'Actual Size of Component Store\s+:\s+(\d+(?:\.\d+)?)\s'
$Matches.1
Gives me this:
pre:
PS C:\Users\NthDoctor> $DISMAnalyze = "Component Store (WinSxS) information:

Windows Explorer Reported Size of Component Store : 11.06 GB

Actual Size of Component Store : 10.60 GB

    Shared with Windows : 6.06 GB
    Backups and Disabled Features : 4.48 GB
    Cache and Temporary Data : 55.69 MB

Date of Last Cleanup : 2019-10-30 08:23:50

Number of Reclaimable Packages : 2
Component Store Cleanup Recommended : Yes

The operation completed successfully."

$DISMAnalyze -match 'Actual Size of Component Store\s+:\s+(\d+(?:\.\d+)?)\s'
$Matches.1
True
10.60

Secx
Mar 1, 2003


Hippopotamus retardus
Stupid PS newbie here. I wrote my first script that verifies all the file paths in an XML file and writes to the console the files that don't exist:

code:
$file = resolve-path(Join-Path $PSScriptRoot "NRInproMenuEN.xml”)
#$root = Read-Host -Prompt "Folder to check"
$root = Get-Content Env:CPAPath

[xml]$menu = Get-Content $file
$paths = $menu.SelectNodes('//mitem') | select path

foreach($path in $paths) {
    if ($path.path) {
        if (!(Test-Path(Join-Path $root $path.path))) {
            Write-Host $root.Trim() + $path.path.Trim()
        }
        
    }
}
Everything works as expected, but when I write the output to the console there is a space between the two variables $root and $path.path. Neither of these variables have a trailing space (I added a Trim() just in case too, but that didn't help) So the output comes out as

\\fileserver\foo\ bar.txt
instead of
\\fileserver\foo\bar.txt

My Google-fu is lacking. Everything I've tried from SO or other Google results don't work.

The Fool
Oct 16, 2003


Secx posted:

Stupid PS newbie here. I wrote my first script that verifies all the file paths in an XML file and writes to the console the files that don't exist:

code:
$file = resolve-path(Join-Path $PSScriptRoot "NRInproMenuEN.xml”)
#$root = Read-Host -Prompt "Folder to check"
$root = Get-Content Env:CPAPath

[xml]$menu = Get-Content $file
$paths = $menu.SelectNodes('//mitem') | select path

foreach($path in $paths) {
    if ($path.path) {
        if (!(Test-Path(Join-Path $root $path.path))) {
            Write-Host $root.Trim() + $path.path.Trim()
        }
        
    }
}
Everything works as expected, but when I write the output to the console there is a space between the two variables $root and $path.path. Neither of these variables have a trailing space (I added a Trim() just in case too, but that didn't help) So the output comes out as

\\fileserver\foo\ bar.txt
instead of
\\fileserver\foo\bar.txt

My Google-fu is lacking. Everything I've tried from SO or other Google results don't work.

It's actually weirder to me that you're not seeing "\\fileserver\foo\ + bar.txt" as your output.

Do your concatenation in another variable, then output it.

ie:
code:
if (!(Test-Path(Join-Path $root $path.path))) {
  $tempPath = $root + $path.path
  Write-Host $tempPath
}
You could probably get away with:
code:
if (!(Test-Path(Join-Path $root $path.path))) {
  Write-Host $root$path.path
}
But I don't feel like that's very clean and would prefer to explicitly join strings.

Toast Museum
Dec 3, 2005

30% Iron Chef

The Fool posted:

Did you have a chance to try the .net method? I'm curious if the behavior is different in your use case or not.

Same question, because Test-Path just seems kinda fucky. Test-Path " " evaluates to true in PowerShell 5.1, for instance. I don't think I've produced any false negatives yet, but it's already enough to make me lean towards [System.IO.File]::Exists("C:\Path\To.File")


Submarine Sandpaper posted:

$DISMAnalyze = & "Dism.exe" /Online /Cleanup-Image /AnalyzeComponentStore

and $DISMAnalyze is a system.string
...
Even something simple like
$DismAnalyze.ToString() -match '[0-9]*\.[0-9]*\s\wB'
is giving me a false. For whatever reason I still have to .ToString() it to get a return with -match, whether true or false. Online calcs are saying this should return all instances of *.* GB or *.* MB.

I'm going crazy.

$DismAnalyze is an array with each line as a member. $DismAnalyze.ToString() returns the string System.Object[], and that's what your regex is matching against. Scrolling back up, I see that I ended up doing the matching pretty similarly to how The Fool did it:
code:
(($DismAnalyze -like "actual*") -split " : ")[1]

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

Toast Museum posted:

Same question, because Test-Path just seems kinda fucky. Test-Path " " evaluates to true in PowerShell 5.1, for instance. I don't think I've produced any false negatives yet, but it's already enough to make me lean towards [System.IO.File]::Exists("C:\Path\To.File")
I haven't tried it yet mostly because I have to test any changes over an interval to build confidence and I was hoping to find something concrete. I also wanted to comb my history first and see if I had already tried it, but it looks like I didn't try it for this particular situation--or at least I didn't find it.

Before toying with that, I'm going to try a different tact. That C:\vagrant directory is a share that vagrant is creating between the Linux hosting environment and Windows. I believe it's using VirtualBox's filesystem to create it, and that is its own can of worms. So I'm going to be googling around about that and see if there's a command to grab something by the face and force a refresh of the file system.

Edit: Looks like the main thing to do with Virtualbox is make sure I updated the guest additions on the images, which I can't readily do from where I am sitting right now, so I'll roll out the System.IO.File test first until I can buff the VM image.

Rocko Bonaparte fucked around with this message at 20:39 on Oct 30, 2019

Secx
Mar 1, 2003


Hippopotamus retardus

The Fool posted:

It's actually weirder to me that you're not seeing "\\fileserver\foo\ + bar.txt" as your output.

Do your concatenation in another variable, then output it.

ie:
code:
if (!(Test-Path(Join-Path $root $path.path))) {
  $tempPath = $root + $path.path
  Write-Host $tempPath
}

Thanks! Using a temp variable did the trick.

PS is pretty cool. For my second script, I'm checking files the other around: recursively find all files matching an extension pattern and check if any are not listed any of my XML attribute nodes (i.e. they are orphans on the fileserver). This is what I came up with and it seems to work. Are there any shortcuts or neat PS tricks I could've used?

code:
$file = resolve-path("\\fileserver\NRInproMenuEN.xml”)
$root = Get-Content Env:CPAPath
$subfolder = Read-Host -Prompt "Subfolder to check (e.g. Foo\Bar\English)"
$tmpFolder = Join-Path $root $subfolder

[xml]$menu = Get-Content $file
$paths = $menu.SelectNodes('//mitem') | select path | Out-String

$files = Get-ChildItem -Path $tmpFolder -Filter *.dot* -Recurse -File -Name
foreach($file in $files) {
    if (!($paths.Contains($file))) {
        $tempPath = Join-Path $tmpFolder  $file
        $lastModified = Get-Item $tempPath | select -ExpandProperty LastWriteTime 
        Write-Host $lastModified $file
    }
}

Submarine Sandpaper
May 27, 2007


Thanks y'all

Woof Blitzer
Dec 29, 2012

[-]
I got two problems: first is I would like to be able to read the output of an ssh command into the script. Second is I have a legacy process manager that only responds to key inputs. The manager is called by entering "pr" and you scroll though it using "p." I am trying to get my script to loop a key using write-host until the end of the process status page is reached, but I have no idea how to do that. The process status varies for each server and there is not a string at the end of each that's universally the same which I could use to tell the loop to end.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

Rocko Bonaparte posted:

so I'll roll out the System.IO.File test first until I can buff the VM image.

It already failed 2-for-2. System.IO.File.Exists for whatever reason looks even worse, or that's just the stats doing stats stuff.

The Fool
Oct 16, 2003


If your testing for a directory use
code:
[System.IO.Directory]::Exists("C:\testpath")

The Fool
Oct 16, 2003


Woof Blitzer posted:

I got two problems: first is I would like to be able to read the output of an ssh command into the script. Second is I have a legacy process manager that only responds to key inputs. The manager is called by entering "pr" and you scroll though it using "p." I am trying to get my script to loop a key using write-host until the end of the process status page is reached, but I have no idea how to do that. The process status varies for each server and there is not a string at the end of each that's universally the same which I could use to tell the loop to end.

First problem is easy, you do something along the lines of:
code:
$results = & "ssh" fool@contoso.com
# disclaimer: did not test
and what would have normally been printed to the screen should be in that variable. The biggest issue is that it will be a string, you'd have deal with that somehow. See the question from Submarine Sandpaper earlier today.

problem two is harder, and as useful as powershell is, something like that might be better solved with AutoHotkey or similar.

Toast Museum
Dec 3, 2005

30% Iron Chef

Rocko Bonaparte posted:

I haven't tried it yet mostly because I have to test any changes over an interval to build confidence and I was hoping to find something concrete. I also wanted to comb my history first and see if I had already tried it, but it looks like I didn't try it for this particular situation--or at least I didn't find it.

Before toying with that, I'm going to try a different tact. That C:\vagrant directory is a share that vagrant is creating between the Linux hosting environment and Windows. I believe it's using VirtualBox's filesystem to create it, and that is its own can of worms. So I'm going to be googling around about that and see if there's a command to grab something by the face and force a refresh of the file system.

Edit: Looks like the main thing to do with Virtualbox is make sure I updated the guest additions on the images, which I can't readily do from where I am sitting right now, so I'll roll out the System.IO.File test first until I can buff the VM image.

Oh, yeah, a share mapped to a folder could complicate things. Whether PowerShell can see it might depend on what context the script runs in, if that varies. This reminds me that I've had Copy-Item claim that a path doesn't exist despite successfully copying items to it, I think because of some kind of identity mismatch.

Re: Guest Additions, there's a Chocolatey package for it that you might be able to use or borrow code from to get an update out.

Fake edit:

Rocko Bonaparte posted:

It already failed 2-for-2. System.IO.File.Exists for whatever reason looks even worse, or that's just the stats doing stats stuff.

It looks like these .NET methods have the same issues regarding the session the script runs in vs. the session the share was mapped in. For instance, my domain user account at work has a HomeDrive mapped to U:. If I run PowerShell as administrator, I can't access U: unless I do New-PSDrive. Even after I do that, though, [System.IO.Directory]::exists("u:\") returns false. What does seem to consistently work is giving the .NET methods the UNC path for the file/folder. For VirtualBox, by default the UNC path should start with \\VBOXSVR


Woof Blitzer posted:

I got two problems: first is I would like to be able to read the output of an ssh command into the script. Second is I have a legacy process manager that only responds to key inputs. The manager is called by entering "pr" and you scroll though it using "p." I am trying to get my script to loop a key using write-host until the end of the process status page is reached, but I have no idea how to do that. The process status varies for each server and there is not a string at the end of each that's universally the same which I could use to tell the loop to end.

If you need to send keystrokes, Write-Host won't get the job done. It sounds like [System.Windows.Forms.SendKeys]::SendWait(string) might work here, though. The documentation for SendKeys.Send shows how to send special characters. As far as identifying when you've reached the end, I'm not sure, since it sounds like there's nothing returned for PowerShell to look out for.

mystes
May 31, 2006

Woof Blitzer posted:

Second is I have a legacy process manager that only responds to key inputs. The manager is called by entering "pr" and you scroll though it using "p." I am trying to get my script to loop a key using write-host until the end of the process status page is reached, but I have no idea how to do that. The process status varies for each server and there is not a string at the end of each that's universally the same which I could use to tell the loop to end.
You probably need to use .net stuff like System.Diagnostics.Process for that because I don't think the powershell Start-Process cmdlet lets you capture the process's standardoutput and write to its standardinput for some inexplicable reason.

nielsm
Jun 1, 2009



Toast Museum posted:

If you need to send keystrokes, Write-Host won't get the job done. It sounds like [System.Windows.Forms.SendKeys]::SendWait(string) might work here, though. The documentation for SendKeys.Send shows how to send special characters. As far as identifying when you've reached the end, I'm not sure, since it sounds like there's nothing returned for PowerShell to look out for.

Those functions are only for faking keyboard input to other local GUI applications. They're most likely not suited for controlling an SSH session, especially not one you connected to via PS. It might sort-of work if you used PuTTY or another not-windows-builtin-console application, but then you'd still have the SSH connection pop up on a separate window, and need to figure out a way to read back the contents.

What you want to do is start the ssh process and connects its stdin and stdout to pipes, then read and write from those.

Toast Museum
Dec 3, 2005

30% Iron Chef
poo poo, yeah, I forgot about the SSH part of the equation :doh:

Woof Blitzer
Dec 29, 2012

[-]
I have had some success calling Plink from powershell but I thought there might be a way to do it all in powershell alone. It’s not the end of the world since I can just ps -ef on the target system but certain old timers like the extra crap that the proprietary process monitor spits out.

mystes
May 31, 2006

Woof Blitzer posted:

I have had some success calling Plink from powershell but I thought there might be a way to do it all in powershell alone. It’s not the end of the world since I can just ps -ef on the target system but certain old timers like the extra crap that the proprietary process monitor spits out.
If the remote computer is a unix system you should probably just be passing something like the following as the command to run to ssh
code:
(echo pr; yes p) | /usr/bin/myprocessmanager
That way there shouldn't be any need to interact with the process from powershell.

Methanar
Sep 26, 2013

by the sex ghost

Woof Blitzer posted:

I got two problems: first is I would like to be able to read the output of an ssh command into the script. Second is I have a legacy process manager that only responds to key inputs. The manager is called by entering "pr" and you scroll though it using "p." I am trying to get my script to loop a key using write-host until the end of the process status page is reached, but I have no idea how to do that. The process status varies for each server and there is not a string at the end of each that's universally the same which I could use to tell the loop to end.

Use GNU expect for dealing with interactive programs.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

The Fool posted:

If your testing for a directory use
code:
[System.IO.Directory]::Exists("C:\testpath")

Yeah it's probably this, first and foremost.

FISHMANPET
Mar 3, 2007

Sweet 'N Sour
Can't
Melt
Steel Beams

Rocko Bonaparte posted:

code:
while((Test-Path C:\vagrant\trampoline\in) -eq $false -and $retries -lt $trampoline_retries) {

I agree with everything Toast Museum said but I'd wanna modify this test as well. I'm not 100% sure what the order of operations for evaluating boolean conditions is and I've found a lot of time where ambiguity in definition leads to strange results. I'd also avoid checking if something equals false, so I'd write this:
code:
while (((-not (test-path "C:\vagrant\trampoline\in")) -and ($retries -lt $trampoline_retries))
It's more parens but it's explicity about what you're checking for. You're checking that test-path returns False, AND you're checking that retries is less than trampoline_retries. Both your way and my way seem to return the same value when I test locally, but it's still something I'd call out on a code review. Also put it in quotes just to be safe, even though it doesn't actually have any spaces in it. But it's really strange that it sometimes works and sometimes doesn't.

Since this is running through some kind of automation, I'd take a close look at permissions. Make sure whatever user this script will run as can read that file. That's usually one of my troubleshooting steps if it works for me, is test and debug against as similar an environment as the real failure as possible.

Secx posted:

code:
$file = resolve-path("\\fileserver\NRInproMenuEN.xml")
Calling the command like this works, but not the way I suspect you think it does. Cmdlets aren't called like functions in other languages, you're lucky here that the interpreter is putting a space between "resolve-path" and your parenthesis so it just thinks it's wrapping that string into a grouping, but you don't need the parenthesis and it's a bad habit you'll want to get out of. Now there's also stuff like [System.IO.Directory]::Exists("C:\testpath") where you do need the parenthesis, because you're passing stuff into a method of the class [System.IO.Directory], or $menu.SelectNodes('//mitem') where you're calling a method on the $menu object.
There's also a copy/pasted back double quote from Word or some blog that auto formats, the interpreter will understand it but it'd be better to ensure it's a standard ASCII double quote.

Also a few tricks for working with strings and properties.
Write-Host $root$path.path won't work, it will print out the string value of $root and then the string representation of the entire path object and then literally ".path". This is a way to use properties in strings:
code:
Write-Host "$root$($path.path)"
You can do pretty much whatever you want inside that $(). You can look at properties of objects, array indexes, even entire new commands:
code:
Write-Host "Path is $(join-path $root $path.path)"
Though in your case sticking with things like join-path is good because it means you don't need to worry about which way the slashes go (Powershell is cross platform you know!) is another good habit to get into.

Pile Of Garbage
May 28, 2007



FISHMANPET posted:

I agree with everything Toast Museum said but I'd wanna modify this test as well. I'm not 100% sure what the order of operations for evaluating boolean conditions is and I've found a lot of time where ambiguity in definition leads to strange results. I'd also avoid checking if something equals false, so I'd write this:
code:
while (((-not (test-path "C:\vagrant\trampoline\in")) -and ($retries -lt $trampoline_retries))
It's more parens but it's explicity about what you're checking for. You're checking that test-path returns False, AND you're checking that retries is less than trampoline_retries. Both your way and my way seem to return the same value when I test locally, but it's still something I'd call out on a code review. Also put it in quotes just to be safe, even though it doesn't actually have any spaces in it. But it's really strange that it sometimes works and sometimes doesn't.

Whenever you're unsure about PowerShell language features you should always refer to the PowerShell About topics. These topics are included with PowerShell itself and can be read locally with Get-Help (Use Get-Help -Category HelpFile to list all available topics).

In this instance the about_Logical_Operators topic explains that the -not logical operator negates only the statement which immediately follows it. IMO it's best to use the ! operator instead of -not. They both function identically however the former can be more cleanly associated with its corresponding statement.

With all this in mind the expression in question could be refactored as follows:

code:
while (!(test-path "C:\vagrant\trampoline\in") -and ($retries -lt $trampoline_retries))
Also as I've mentioned before in this thread when using the Test-Path cmdlet you should always include the PathType parameter to specify whether you are expecting a file or directory.

Pile Of Garbage
May 28, 2007



Figured I'd include a general tip for all to balance out the nitty-gritty. If you're working with URLs then the System.Uri class is your best friend. Its constructor accepts a string so it's an excellent way to parse URLs and extract specific components:

pre:
PS C:\> [System.Uri]$Uri = 'http://www.example.com:8081/foo/bar.htm?foo=bar'
PS C:\> $Uri

AbsolutePath   : /foo/bar.htm
AbsoluteUri    : http://www.example.com:8081/foo/bar.htm?foo=bar
LocalPath      : /foo/bar.htm
Authority      : www.example.com:8081
HostNameType   : Dns
IsDefaultPort  : False
IsFile         : False
IsLoopback     : False
PathAndQuery   : /foo/bar.htm?foo=bar
Segments       : {/, foo/, bar.htm}
IsUnc          : False
Host           : www.example.com
Port           : 8081
Query          : ?foo=bar
Fragment       :
Scheme         : http
OriginalString : http://www.example.com:8081/foo/bar.htm?foo=bar
DnsSafeHost    : www.example.com
IdnHost        : www.example.com
IsAbsoluteUri  : True
UserEscaped    : False
UserInfo       :
It won't throw an exception if an invalid URL is used. Instead the IsAbsoluteUri property will be set to False making it a good way to also validate URLs:

pre:
PS C:\> ([System.Uri]'garbage').IsAbsoluteUri
False
Some other useful tests:

pre:
PS C:\> ([System.Uri]'http://10.0.0.1').HostNameType
IPv4
PS C:\> ([System.Uri]'http://127.0.0.1').IsLoopback
True

Pile Of Garbage fucked around with this message at 13:14 on Nov 1, 2019

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


Pile Of Garbage posted:

Figured I'd include a general tip for all to balance out the nitty-gritty. If you're working with URLs then the System.Uri class is your best friend. Its constructor accepts a string so it's an excellent way to parse URLs and extract specific components:

pre:
PS C:\> [System.Uri]$Uri = 'http://www.example.com:8081/foo/bar.htm?foo=bar'
PS C:\> $Uri

AbsolutePath   : /foo/bar.htm
AbsoluteUri    : http://www.example.com:8081/foo/bar.htm?foo=bar
LocalPath      : /foo/bar.htm
Authority      : https://www.example.com:8081
HostNameType   : Dns
IsDefaultPort  : False
IsFile         : False
IsLoopback     : False
PathAndQuery   : /foo/bar.htm?foo=bar
Segments       : {/, foo/, bar.htm}
IsUnc          : False
Host           : https://www.example.com
Port           : 8081
Query          : ?foo=bar
Fragment       :
Scheme         : http
OriginalString : http://www.example.com:8081/foo/bar.htm?foo=bar
DnsSafeHost    : https://www.example.com
IdnHost        : https://www.example.com
IsAbsoluteUri  : True
UserEscaped    : False
UserInfo       :
It won't throw an exception if an invalid URL is used. Instead the IsAbsoluteUri property will be set to False making it a good way to also validate URLs:

pre:
PS C:\> ([System.Uri]'garbage').IsAbsoluteUri
False
Some other useful tests:

pre:
PS C:\> ([System.Uri]'http://10.0.0.1').HostNameType
IPv4
PS C:\> ([System.Uri]'http://127.0.0.1').IsLoopback
True
Funny, I did exactly this yesterday so I could extract the host from a URL string and get DNS information about it.

We're migrating from one data center to another, and I wanted to give a clue to myself about if my hostfile entries are in place or not, since I'm pretesting the new site.

Otis Reddit
Nov 14, 2006
Hello PS thread. I have a task at hand that I'm wondering if I could use PowerShell to accomplish quickly and efficiently.

I have some 50 or so .htm files in a directory, that I need to delete a string from. I'm thinking that PowerShell could be used for this without me having to open and edit each file. Am I barking up the right tree here?

Thank you,

mystes
May 31, 2006

Otis Reddit posted:

Hello PS thread. I have a task at hand that I'm wondering if I could use PowerShell to accomplish quickly and efficiently.

I have some 50 or so .htm files in a directory, that I need to delete a string from. I'm thinking that PowerShell could be used for this without me having to open and edit each file. Am I barking up the right tree here?

Thank you,
If you can do it just by deleting all instances of a string then you can do it in powershell easily. If you need to actually modify html the right way it's slightly harder because you'll need to use a .net library like the Html Agility Pack.

nielsm
Jun 1, 2009



If it's just a one-shot task, I'd reach for a text editor with multi-file search replace.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

FISHMANPET posted:

I agree with everything Toast Museum said but I'd wanna modify this test as well. I'm not 100% sure what the order of operations for evaluating boolean conditions is and I've found a lot of time where ambiguity in definition leads to strange results. I'd also avoid checking if something equals false, so I'd write this:
Just to be certain here: when talking about "ambiguity" and things like that, are we talking sometimes it does one thing and sometimes another? My situation is statistical right now and I want to know where something could be inconsistent. I'd expect these boolean conditions to work consistently. I mean, garbage-in-garbage-out in terms of the variables, but I wouldn't expect Powershell to decide to change the order of operations run-to-run. That would be a real kick in the pants.

I'm hoping to reduce that huge block of code if things start to improve between using System.IO.Directory::Exists and updating the VirtualBox guest additions. So far, I have not had that particular problem surface yet after 8-10 runs. I will consider moving the logic back in the script that is launching the task in the first place because it occurred much more frequently from there.

Mostly, this is just me writing back that I'm still keeping an eye on this, but I need to run it many more times before I have much to say definitively.

Pile Of Garbage
May 28, 2007



Rocko Bonaparte posted:

Just to be certain here: when talking about "ambiguity" and things like that, are we talking sometimes it does one thing and sometimes another? My situation is statistical right now and I want to know where something could be inconsistent. I'd expect these boolean conditions to work consistently. I mean, garbage-in-garbage-out in terms of the variables, but I wouldn't expect Powershell to decide to change the order of operations run-to-run. That would be a real kick in the pants.

All operators in PowerShell behave consistently as documented which I mentioned in an earlier post.

Judge Schnoopy
Nov 2, 2005

dont even TRY it, pal

nielsm posted:

If it's just a one-shot task, I'd reach for a text editor with multi-file search replace.

Yeah if you don't care about the aspect of learning powershell, open the folder in visual studio code, search all for the string, replace with "".

If you want to do it just to practice powershell it can absolutely be done.

Jethro
Jun 1, 2000

I was raised on the dairy, Bitch!

Rocko Bonaparte posted:

Just to be certain here: when talking about "ambiguity" and things like that, are we talking sometimes it does one thing and sometimes another? My situation is statistical right now and I want to know where something could be inconsistent. I'd expect these boolean conditions to work consistently. I mean, garbage-in-garbage-out in terms of the variables, but I wouldn't expect Powershell to decide to change the order of operations run-to-run. That would be a real kick in the pants.

Pile Of Garbage posted:

All operators in PowerShell behave consistently as documented which I mentioned in an earlier post.
Right, FISHMANPET was talking about ambiguity in terms of how Powershell interprets a statement versus the ways a person could interpret it. Powershell is going to do the same thing every time, but if you've got a complicated enough expression, what Powershell does may not be what the writer intended, or what the next person reading the code thinks is going to happen, unless they've got the About Operator Precedence reference open on another monitor. So liberally sprinkling parentheses in your comparisons can help signal intent and make sure what you tell Powershell to do is what you meant it to do.

I know that test-thing "parameter" -eq $false -and $vara -eq $varb means (and will always mean) the same thing as (test-thing "parameter" -eq $false) -and ($vara -eq $varb) in Powershell, but will everyone reading it (including the future me who didn't just read the help file) know that, or will someone think it could mean test-thing "parameter" -eq ($false -and $vara -eq $varb) and then do something stupid based on that (admittedly implausible in this case) incorrect reading? Whereas there's pretty much only one way for a person to interpret (!(test-thing "parameter")) -and ($vara -eq $varb), and that is also the way Powershell will interpret it.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

Jethro posted:

I know that test-thing "parameter" -eq $false -and $vara -eq $varb means (and will always mean) the same thing as (test-thing "parameter" -eq $false) -and ($vara -eq $varb) in Powershell, but will everyone reading it (including the future me who didn't just read the help file) know that, or will someone think it could mean test-thing "parameter" -eq ($false -and $vara -eq $varb) and then do something stupid based on that (admittedly implausible in this case) incorrect reading? Whereas there's pretty much only one way for a person to interpret (!(test-thing "parameter")) -and ($vara -eq $varb), and that is also the way Powershell will interpret it.

Fair enough there. I don't have anybody else to really review the code in general. And I want to reiterate that I was getting genuinely worried that it could somehow get run differently based on God-knows-what.

As a side note, updating Virtualbox's drivers as well as using System.IO.Directory did not fix the problem of the directory not being detected sometimes. I'm now trying a path outside of the shared folder. I had it in the shared folder for tracking. If that doesn't work, then I'm throwing up my hands and using whatever inter-process notification mechanism I can get to work between Python and PowerShell... probably a socket unless I can find something lazier.

Toast Museum
Dec 3, 2005

30% Iron Chef

Rocko Bonaparte posted:

Fair enough there. I don't have anybody else to really review the code in general. And I want to reiterate that I was getting genuinely worried that it could somehow get run differently based on God-knows-what.

As a side note, updating Virtualbox's drivers as well as using System.IO.Directory did not fix the problem of the directory not being detected sometimes. I'm now trying a path outside of the shared folder. I had it in the shared folder for tracking. If that doesn't work, then I'm throwing up my hands and using whatever inter-process notification mechanism I can get to work between Python and PowerShell... probably a socket unless I can find something lazier.

Taking VirtualBox's folder sharing out of the equation for now makes sense. Is the script always run with the same credentials, and does that account have the same permissions on all of the devices the script is run on?

Toast Museum
Dec 3, 2005

30% Iron Chef
Question about PSRemoting over SSH: am I misunderstanding the docs, or is there no way to avoid entering a password per session? Sounds like providing user credentials and providing a keyfile both involve being prompted for a password. Is there any decent way to Invoke-Command to a bunch of non-Windows machines?

mystes
May 31, 2006

Toast Museum posted:

Question about PSRemoting over SSH: am I misunderstanding the docs, or is there no way to avoid entering a password per session? Sounds like providing user credentials and providing a keyfile both involve being prompted for a password. Is there any decent way to Invoke-Command to a bunch of non-Windows machines?
Normally with ssh it's optional to have the key encrypted with a passphrase and aside from that you won't be prompted for a password when using public key authentication.

Toast Museum
Dec 3, 2005

30% Iron Chef

mystes posted:

Normally with ssh it's optional to have the key encrypted with a passphrase and aside from that you won't be prompted for a password when using public key authentication.

The passphrase has to be provided when you connect, though, right? It doesn't look like there's a way to supply it in a parameter, so the host prompts for it. If I'm trying to send a command to multiple machines, it sounds like I've got to enter the passphrase separately for each machine.

Edit: wait, do you mean that the passphrase is optional? That does help. In that case, is there a good way to automate putting the keys in place for a bunch of machines?

Toast Museum fucked around with this message at 22:28 on Nov 5, 2019

Adbot
ADBOT LOVES YOU

mystes
May 31, 2006

Toast Museum posted:

Edit: wait, do you mean that the passphrase is optional? That does help. In that case, is there a good way to automate putting the keys in place for a bunch of machines?
Yeah you don't need to set a passphrase for the key. All it does is encrypt the private key file in case it gets stolen from your computer somehow.

If you just want to be able to log in from one computer to a bunch of other computers, you just have to append the contents of the id_(whatever).pub file from the one computer to the authorized_keys file on each of the computers you want to be able to connect to.

(Openssh on other platforms has a script just for this called "ssh-copy-id" but you don't need to use that.)

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