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
Mario
Oct 29, 2006
It's-a-me!
In that case you just do the formatting with Foreach-Object and use Out-File to write the .bat file directly:
code:
Get-ChildItem -Filter *.msu -Name | Foreach-Object { "fancy.exe $_ /flag1 /flag2" } | Out-File fancy.bat

Adbot
ADBOT LOVES YOU

Mario
Oct 29, 2006
It's-a-me!

i barely GNU her! posted:

code:
$info = Get-Item butts.txt
if($info.CreationTime.DayOfWeek -ne "Saturday" -and $info.CreationTime.DayOfWeek -ne "Sunday" -and $info.CreationTime.Day -lt 4)
{
    # it was the first weekday of the month
}
First we need to check if the creation time is not on a weekend, then make sure it's prior to the fourth day of the month (for the case where first day of the month is a Friday). Every other case should be covered but I haven't actually tested it.
What if the 1st is on a Monday? This would match Tuesday and Wednesday as well.

How about (again, not tested):
code:
$info = Get-Item butts.txt
if(($info.CreationTime.DayOfWeek -ne "Saturday" -and $info.CreationTime.DayOfWeek -ne "Sunday" -and $info.CreationTime.Day -eq 1)
-or
($info.CreationTime.DayOfWeek -eq "Monday" -and $info.CreationTime.Day -lt 4))
{
    # it was the first weekday of the month
}

Mario
Oct 29, 2006
It's-a-me!
How about \d{1,3}(\,\d{3})*

1 to 3 digits at the start, followed optionally by any number of ,ddd groups.

Mario
Oct 29, 2006
It's-a-me!
I think you could simplify this a great deal by using a StreamReader to wrap the response stream. Haven't tested it though.

Something like this, picking up partway through your code. It checks against an empty string in case there are trailing newlines.
code:
$ftpresponse = $ftpconn.getresponse()
$ftpstream = $ftpresponse.getresponsestream()

$reader = New-Object System.IO.StreamReader($ftpStream)

while ($reader.EndOfStream -eq $false)
{
	$curLine = $reader.readLine()
	if ($curLine -ne '')
	{
		$lastLine = $curLine
	}
}

# Parse out $lastLine by tabs or whatever

Mario
Oct 29, 2006
It's-a-me!
Do you have to single quote the string instead of escaping the double quotes with backticks? Single quoted strings are not supposed to do variable expansions.
code:
"$variable blahblahblah somestuff `"powershell is really pissing me off`""

Mario
Oct 29, 2006
It's-a-me!

stubblyhead posted:

How would you guys handle this kind of situation? I want to randomly arrange a collection. I can do it like this:
code:
$random = Get-Random -InputObject $myCollection -Count $myCollection.Length
but it doesn't work if $myCollection only has a single element. I'm not sure if this is how the PowerCLI cmdlets are written or if it's just how Powershell works, but the Get-Cluster cmdlet will return a single object if there's only one that matches the criteria, and a collection of them if there's multiple. The Cluster object doesn't have a Length property, so Get-Random thrown an error because the parameter gets passed a null value. I'd prefer not to do a check on the length before doing this if possible. Is there any way I can make it handle a single object as a collection with length 1, or is there just a better way to approach this altogether?
You can also use @ to force the object to behave as an array:
code:
PS> (1, 2, 3 | Get-Random -Count 1).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Int32                                    System.ValueType


PS> @(1, 2, 3 | Get-Random -Count 1).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Mario
Oct 29, 2006
It's-a-me!

AreWeDrunkYet posted:

Is there a workaround, or some null value I could use that wouldn't throw off the send-mailmessage cmdlet?

e: Found a workaround, just dimmed a new cc array and went through each of the items in the existing cc array, adding the non-blank ones to the new array. Then I used the new array with send-mailmessage. Not the most elegant solution, but works.
I would just use Where-Object to filter out the blanks:
code:
send-mailmessage -to $recipient -from $from -cc ($cc | Where-Object { $_ -ne [string]::Empty })

Mario
Oct 29, 2006
It's-a-me!

Factor Mystic posted:

Thanks for the tip, but as you said there's no timestamp and I also couldn't figure out how to get it to ping forever (though, to be fair neither did the script I posted).
I took a stab at this starting with your code and got something going. Basically, keep sending the output down the pipeline as you go, and have a single Format-Table to read in the pipeline. Also, -AutoSize seems to gather all the input first in order to know how to size the table, so that's no good.
PowerShell code:
[CmdletBinding()]
Param (
    [int32]$count = 5,
    
    [Parameter(ValueFromPipeline=$true)]
    [String[]]$computer = "google.com"
)

function Run-Ping {
    while ($count -gt 0) {
        $ping = Get-WmiObject Win32_PingStatus -Filter "Address = '$computer'" | Select @{Label="TimeStamp"; Expression={Get-Date}}, 
                                                   @{Label="Source"; Expression={ $_.__Server }},
                                                   @{Label="Destination"; Expression={ $_.Address }},
                                                   IPv4Address,
                                                   ResponseTime,
                                                   @{Label="Status"; Expression={ if ($_.StatusCode -ne 0) { "Failed" } else {"OK"}}}
        
        $ping | Select TimeStamp, Destination, IPv4Address, ResponseTime, Status

        $count--
        Start-Sleep -Seconds 1
    }
}

Run-Ping | Format-Table
This gives nice table which updates throughout the process.
pre:
TimeStamp               Destination             IPV4Address                        ResponseTime Status
---------               -----------             -----------                        ------------ ------
8/8/2013 20:04:01       google.com              74.125.142.113                               21 OK
8/8/2013 20:04:02       google.com              74.125.142.113                               19 OK
8/8/2013 20:04:03       google.com              74.125.142.113                               21 OK
8/8/2013 20:04:04       google.com              74.125.142.113                               20 OK
8/8/2013 20:04:05       google.com              74.125.142.113                               21 OK
Or instead of piping to Format-Table, pipe it to Out-Gridview for a lightweight GUI with sort/filter, that also updates as it runs.

e: tables

Mario fucked around with this message at 03:08 on Aug 9, 2013

Mario
Oct 29, 2006
It's-a-me!

TheEffect posted:

I noticed that the directory it was giving was cut-off at a space character. I changed the name of the folder by replacing the spaces with underscore and it works perfectly. Still not sure why though.
You probably had something like this as your shortcut:
code:
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe C:\Users\User1\New Folder\script.ps1
Instead of quoting the full path:
code:
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe "C:\Users\User1\New Folder\script.ps1"

Mario
Oct 29, 2006
It's-a-me!
Does this work in v2?
code:
(Get-Content file.csv) | ConvertFrom-CSV
The idea is to let Get-Content handle the line breaking and pass it as a string array to ConvertFrom-CSV.

Mario
Oct 29, 2006
It's-a-me!

FISHMANPET posted:

I guess I could also do a switch statement on $PSCmdlet.ParameterSetName but that doesn't change the meat of the problem which is that I'm having to define my "default" twice. I also don't know which is better coding practice, what I've got above or switch on ParameterSetName.
$allFields is a mandatory switch, so it will never be $false when invoked with the "All" parameter set(e: nope, can be forced to false with -allFields:$false, but it seems awkward to do that. Still you can get this "switch always true" behavior with a validation set). Maybe have a third parameter set "Default"?
code:
    Param (
        [Parameter(Mandatory = $True, ParameterSetName = "All")]
        [ValidateSet($True)]
        [switch]$AllFields
        ,
        [Parameter(Mandatory = $True, ParameterSetName = "Default")]
        [ValidateSet($True)]
        [switch]$DefaultFields
        ,
        [Parameter(Mandatory = $True, ParameterSetName = "Specify")]
        [string]$FieldList
        ,
        [Parameter(Mandatory = $True)]
        [string]$AccessToken
    )
    
    if ($AllFields)
    {
        
    }
    elseif ($DefaultFields)
    {
        
    }
    else
    {
        # Use FieldList
    }

Mario fucked around with this message at 03:08 on Feb 20, 2019

Mario
Oct 29, 2006
It's-a-me!

FISHMANPET posted:

Maybe I'm not quite understanding, because if you set the ValidateSet to only $True then you can't do -param:$false. Now granted, setting switches to true by default is apparently against best practice so I guess it's kind of weird that I'm asking "what's the best way to follow best practices when I'm violating best practices."
I could definitely be using switch parameters "wrong" there, with the idea that you'd never want to set any of them to $false and just have three parameter sets for the three modes (all fields, default fields, specific fields). Looks like you've arrived at something even simpler in the end.

Mario
Oct 29, 2006
It's-a-me!

Wizard of the Deep posted:

Use "get-help get-adcomputer" to get a better idea of how to use the command.
Also Show-Command is great for discovering parameters.

Mario
Oct 29, 2006
It's-a-me!
It looks like you can just read values by square-bracket indexing with the key, but this is documented as the Item property since that's the underlying CLR property name:

https://github.com/aws/aws-sdk-net/blob/1a5187e0dcddadba10a6b90fd827f2e485af0f9c/sdk/src/Services/S3/Custom/Model/MetadataCollection.cs#L38

Mario
Oct 29, 2006
It's-a-me!
Can only guess why it was designed that way, but your observation is because the cmdlet throws an exception (and never writes the response back to your variable). The exception throw can be disabled in PowerShell 7 and the PR for it offers some insight.

Mario
Oct 29, 2006
It's-a-me!

Toshimo posted:

Trying to set something up for an installer and this is bugging the hell out of me.

CODE:
code:
$MSIResultCodes = (
    @{"0"="SUCCESS: Task Successful"},
    @{"1605"="SUCCESS: Task Successful - App not Installed"},
    @{"1618"="Failure: Another install in Progress"},
    @{"3010"="SUCCESS: Task Successful - Reboot Required"}
)

$ExitCode="1605"

$MSIResultCodes.$ExitCode
Works perfectly. Except if I turn strict mode on and get a PropertyNotFoundException for the last line.
You have $MSIResultCodes as an array of hashtables. Piping it to Get-Member claims it's a Hashtable because that's what the array is composed of, but $MSIResultCodes.GetType() doesn't try to be helpful like that and reveals the truth.

Try
code:
$MSIResultCodes = @{
    "0"="SUCCESS: Task Successful";
    "1605"="SUCCESS: Task Successful - App not Installed";
    "1618"="Failure: Another install in Progress";
    "3010"="SUCCESS: Task Successful - Reboot Required"
}

Mario
Oct 29, 2006
It's-a-me!
$AAs gets overwritten with each loop over $RGs, so it makes sense that only the last retrieved value is available. Also, building arrays and looping with foreach..in feels awkward in PS rather than using the pipeline.

Try something like:
code:
$Subscriptions = @('Sub1','Sub2','Sub3')

$AAs = $Subscriptions | Foreach-Object { Set-AzContext | Out-Null; Get-AzAutomationAccount }
Each invocation of Get-AzAutomationAccount puts its results onto the pipeline because we don't assign it to a variable. These get flattened into a single collection and assigned to $AAs. Set-AzContext has its output piped to Out-Null (much like /dev/null) so it does not pollute the main pipeline result. Get-AzResourceGroup is omitted since it appears you want to get automation accounts in all resource groups anyways.

Mario
Oct 29, 2006
It's-a-me!
Do you actually need to involve cmd.exe? It seems simpler to remove items and run the uninstaller/gpupdate from PS directly.

Mario
Oct 29, 2006
It's-a-me!
Taking advantage of the taxes value always being duplicated, you can remove it from the grouping and instead take an aggregation on it (min, max, avg) to get the desired result:

PowerShell code:
$csvmath = (Import-Csv $CsvFile |Group-Object Order,Date| `
Select-Object @{Name='Order';Expression={$_.Values[0]}},  `
              @{Name='Shipping' ;Expression={$_.Values[1]}}, `
              @{Name='Taxes';Expression={($_.Group | Measure-Object Taxes -Minimum).Minimum}}, `
              @{Name='Total';Expression={($_.Group | Measure-Object Transact -Sum).Sum}}, `
              @{Name='TotalLessTaxes';Expression={($_.Group | Measure-Object Transact -Sum).Sum - ($_.Group | Measure-Object Taxes -Minimum).Minimum}} `
              )
pre:
Order Shipping Taxes  Total TotalLessTaxes
----- -------- -----  ----- --------------
10043 2/4/22    2.86  33.75          30.89
10044 2/4/22    1.33  15.66          14.33
10045 2/4/22    9.38 123.08          113.7
10046 2/4/22    4.46  52.45          47.99
10047 2/4/22     4.6  54.14          49.54
10048 2/4/22    4.32  50.92           46.6

Mario
Oct 29, 2006
It's-a-me!
continue should do it https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_continue?view=powershell-7.2

Mario
Oct 29, 2006
It's-a-me!
And remember to use -NoTypeInformation on this if you are not on v6+

Mario
Oct 29, 2006
It's-a-me!

Toshimo posted:

Losing my drat mind on this one. Got a bunch of folders I was looking to zip up (and I'll wind up doing with 7zip because this isn't working).

Reduced it to the very basic level (I've tried a dozen flavors of this):
PowerShell code:
gci  . | ForEach-Object -Process { Compress-Archive $_ $_ -Verbose }
The first instance of $_ just returns (or is interpreted as) nothing. Second one is fine.

Output:

VERBOSE: Preparing to compress...
VERBOSE: Performing the operation "Compress-Archive" on target "".
VERBOSE: The partially created archive file 'v:\Marvel\Alias\Alias - 022 [2003].zip' is deleted as it is not usable.
VERBOSE: The archive file path 'v:\Marvel\Alias\Alias - 023 [2003]' supplied to the DestinationPath patameter does not include .zip extension. Hence .zip is appended to the supplied DestinationPath path and the archive file would be created at 'v:\Marvel\Alias\Alias - 023 [2003].zip'.


It's the square brackets -- use LiteralPath instead of Path:
PowerShell code:
Get-ChildItem -Path . -Directory | ForEach-Object -Process { Compress-Archive -LiteralPath $_ -DestinationPath $_ -Verbose }
https://superuser.com/questions/212808/powershell-bug-in-copy-move-rename-when-filename-contains-square-bracket-charac

Also added -Directory to the Get-ChildItem so that it doesn't match the (newly created) zip files.

Mario
Oct 29, 2006
It's-a-me!
I'd really want to use a library to deal with the HTML garbage -- e.g. HTML Agility Pack. Remember that PowerShell is .NET Framework or Core (depending on version), so there are lots of helper libraries out there.

Adbot
ADBOT LOVES YOU

Mario
Oct 29, 2006
It's-a-me!

disaster pastor posted:

Dokan makes them look like actual local drives. I have an application that fails if it sees them as "mounted network locations" instead of local drives.

I'll look into that script. Thanks!

Have you tried to fool the application with subst?

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