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
Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

anthonypants posted:

If you use robocopy inside of PowerShell you can still use variable names as parts of the path or as excluded files/folders, so there's no* reason to use Copy-Item instead.

*Like the only reason I can think of where you might not want to use robocopy is because of its weird exit codes (e.g. inside of a Scheduled Task), but those are fairly well-documented, so you can write a wrapper around those or write them to a log somewhere if you really need to validate them.
I agree with this. I'm usually a proponent of doing things in code instead of shelling out, but robocopy is just superior in roughly every way. The error codes are weird though.


However, this did give me an idea to (yet again) plug my new module Idempotion, which lets you use existing DSC resources directly in scripts.

As it happens, there is an existing xRobocopy DSC resource, so here's how you can use Robocopy with Idempotion:

code:
# You probably just want to run this once, outside of the script itself.
Install-Module Idempotion,xRobocopy -Force

Import-Module Idempotion

Get-DscResource xRobocopy | Convert-DscResourceToCommand -Import -MockWhatIf

Set-xRobocopy -Source 'B:\MySource' -Destination 'C:\MyDestination' -SubdirectoriesIncludingEmpty $true -Verbose -WhatIf  
# ^ Remove -WhatIf to really run it
That's it. The resource is already aware of the error codes and tests for them appropriately.

Note that you can also use Test-xRobocopy with the same parameters, which just checks to see if it's in the correct state, and if you wanted to do a test first/set if necessary, then you would just use Update-xRobocopy instead of writing the if statement yourself.

Adbot
ADBOT LOVES YOU

EssOEss
Oct 23, 2006
128-bit approved
I have a script that does this:

code:
& foo.exe bar baz worp
Because foo.exe writes to stderr as part of its normal (non-error) operation, my PowerShell host says "Oh no, this command failed!" (I think it reads the PowerShell error stream)

code:
& foo.exe bar baz worp 2 > &1
I tried redirecting stderr to stdout as above but this changed nothing. The internet says that it doesn't really work for this purpose anyway.

I also tried -ErrorAction SilentlyIgnore but it just tries to pass it to foo.exe.

How do I modify my script to stop it seeing the errors and freaking out (but only on this one line)?

The Fool
Oct 16, 2003


Tried wrapping it in a try/catch?

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

EssOEss posted:

I have a script that does this:

code:
& foo.exe bar baz worp
Because foo.exe writes to stderr as part of its normal (non-error) operation, my PowerShell host says "Oh no, this command failed!" (I think it reads the PowerShell error stream)

code:
& foo.exe bar baz worp 2 > &1
I tried redirecting stderr to stdout as above but this changed nothing. The internet says that it doesn't really work for this purpose anyway.

I also tried -ErrorAction SilentlyIgnore but it just tries to pass it to foo.exe.

How do I modify my script to stop it seeing the errors and freaking out (but only on this one line)?
What's the return/exit code for that script?

Also, is it '2 > &1' or is it '2>&1'?

Inspector_666
Oct 7, 2003

benny with the good hair
I used to have a script that was a wrapped around GAM, and I had to write the commands like so:

code:
cmd /c .\gam.exe update group $grpNameAdd add member $usrName 2>&1 | %{ "$_" }
Try adding the piped bit at the end, which will turn the output into a string* and should stop Powershell from freaking out.

Note that error handling in this case requires you to scrape the output for the codes though. (I've since re-written it using gShell which makes my life much easier even if there are some API hooks missing from that module.)


*Is that right? I'm pretty sure I just lifted that workaround wholesale from Stack Overflow.

Inspector_666 fucked around with this message at 22:00 on Jul 24, 2017

EssOEss
Oct 23, 2006
128-bit approved
What appears to be happening is that this stderr output causes the call operator to write some ErrorRecords to the PowerShell error stream. It does not terminate the script or anything - the problem is that the thing calling the script (a build process) freaks out over those ErrorRecords.

In other words, regardless of what I do with the output of the command (and I have tried everything) it does not matter because the problem is that the stderr entries show up in $Error.

Wrapping it in a cmd /c seems to be the key, though! PowerShell stops seeing stderr once I do that. Good enough for me. If I try to pipe it to stdout then it breaks again but no problem - I do not need the stderr output anyway. Thanks for the suggestions!

Edit: oh for gently caress's sake it randomly works and does not on different runs now. What the hell.

Edit 2: gently caress this poo poo, Start-Process and the hell with doing it in a more natural scriptish way.

EssOEss fucked around with this message at 11:36 on Jul 25, 2017

Modulo16
Feb 12, 2014

"Authorities say the phony Pope can be recognized by his high-top sneakers and incredibly foul mouth."

Hey guys,

I'm an incredibly new Powershell scripter who has been tasked with developing a script that pulls an XML feed, stores the information that I want, and exports it to a csv file. I'm trying to get the script to go further and count the number of instances that occur in the CSV file. I'm running into an Issue where the output csv is showing the count but not the entities that I want also populated.

PowerShell code:
$url = "Path to the Feed"
[xml]$XmlDocument = (new-object System.Net.WebClient).DownloadString($url)
$XmlDocument.GetType().FullName
$XmlDocument
$CurrentTime = Get-Date -Format G
$CurrentDate = Get-Date -Format "MM/dd/yyyy" 
foreach ($obj in $XMLDocument.Devices.Device)
{
    if(($obj.IsInComm -eq "No") -and ($obj.IsFinished -eq "No")-and ($obj.CurrentGroup) -ne "0" -and ($obj.LastCommTime.contains($CurrentDate)))  
    {
        $properties = @{
        CurrentGroup = $obj.CurrentGroup 
        ApplicationType =  $obj.AppType 
        CurrentHole = $obj.CurrentHole 
        LoginName = $obj.LoginName
        LaserLocation = $obj.LaserLocation
        LastCommTime = $obj.LastCommTime
        DisconnectCount = $obj.DisconnectCount

        }
    $Results += New-Object psobject -Property $properties
    
    }
}
$Results | Select-Object CurrentGroup, ApplicationType, CurrentHole, LaserLocation, LoginName, LastCommTime, DisconnectCount | Export-Csv $DataPathNew
Import-Csv $DataPathNew | Export-CSv -Append $RecordPath

import-csv $RecordPath  | Select CurrentGroup, ApplicationType, CurrentHole, LaserLocation, LoginName, LastCommTime, DisconnectCount | 

group CurrentGroup, ApplicationType, CurrentHole, LaserLocation, LoginName, LastCommTime, DisconnectCount, Count | Export-Csv $DataPathAlertPotential
Output Csv:
http://imgur.com/a/NFuJd

I'd like for this to be able to keep original csv column structure if possible. Is there any way I can do this?

Modulo16 fucked around with this message at 21:09 on Jul 27, 2017

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

Frank Viola posted:

Hey guys,

I'm an incredibly new Powershell scripter who has been tasked with developing a script that pulls an XML feed, stores the information that I want, and exports it to a csv file. I'm trying to get the script to go further and count the number of instances that occur in the CSV file. I'm running into an Issue where the output csv is showing the count but not the entities that I want also populated.

PowerShell code:
$url = "Path to the Feed"
[xml]$XmlDocument = (new-object System.Net.WebClient).DownloadString($url)
$XmlDocument.GetType().FullName
$XmlDocument
$CurrentTime = Get-Date -Format G
$CurrentDate = Get-Date -Format "MM/dd/yyyy" 
foreach ($obj in $XMLDocument.Devices.Device)
{
    if(($obj.IsInComm -eq "No") -and ($obj.IsFinished -eq "No")-and ($obj.CurrentGroup) -ne "0" -and ($obj.LastCommTime.contains($CurrentDate)))  
    {
        $properties = @{
        CurrentGroup = $obj.CurrentGroup 
        ApplicationType =  $obj.AppType 
        CurrentHole = $obj.CurrentHole 
        LoginName = $obj.LoginName
        LaserLocation = $obj.LaserLocation
        LastCommTime = $obj.LastCommTime
        DisconnectCount = $obj.DisconnectCount

        }
    $Results += New-Object psobject -Property $properties
    
    }
}
$Results | Select-Object CurrentGroup, ApplicationType, CurrentHole, LaserLocation, LoginName, LastCommTime, DisconnectCount | Export-Csv $DataPathNew
Import-Csv $DataPathNew | Export-CSv -Append $RecordPath

import-csv $RecordPath  | Select CurrentGroup, ApplicationType, CurrentHole, LaserLocation, LoginName, LastCommTime, DisconnectCount | 

group CurrentGroup, ApplicationType, CurrentHole, LaserLocation, LoginName, LastCommTime, DisconnectCount, Count | Export-Csv $DataPathAlertPotential


I'd like for this to be able to keep original csv column structure if possible. Is there any way I can do this?
Firstly, use the url of the image when you're using img or timg. As for the PowerShell, use the -NoTypeInformation flag when you use Export-Csv, and that'll get rid of the first few rows that have the #TYPE garbage in them.The problem you're getting with the Values and Group columns is probably that you're passing some object to those columns instead of a value associated with that object. The problem with the Name column is likely due to your use of Group-Object. Did you mean to use Sort-Object?

anthonypants fucked around with this message at 21:18 on Jul 27, 2017

Modulo16
Feb 12, 2014

"Authorities say the phony Pope can be recognized by his high-top sneakers and incredibly foul mouth."

anthonypants posted:

Firstly, use the url of the image when you're using img or timg. As for the PowerShell, use the -NoTypeInformation flag when you use Export-Csv, and that'll get rid of the first few rows that have the #TYPE garbage in them.The problem you're getting with the Values and Group columns is probably that you're passing some object to those columns instead of a value associated with that object. The problem with the Name column is likely due to your use of Group-Object. Did you mean to use Sort-Object?

This Feed is pulled once per minute. I pull the Objects I need and export them to a csv file, and append it to a master Csv as well. We're trying to see how many times a certain device falls out of communication with our server while in use, and I'm trying to pull duplicate entries in the Master csv to quantify that. The count Column was added to show the quantity of duplicates, and I'm trying to keep the consistency of the file intact, while adding this additional column. Does that make sense? I guess my question would be: "How can I add a column that shows me a count of duplicate entries in a csv?"

Modulo16 fucked around with this message at 22:15 on Jul 27, 2017

thebigcow
Jan 3, 2001

Bully!
Group-Object seems to cram all the details of what was grouped as an object of a "Group" property. If you pipe that through
code:
 Select-Object -ExpandProperty "Group"
does that get you something usable?

Modulo16
Feb 12, 2014

"Authorities say the phony Pope can be recognized by his high-top sneakers and incredibly foul mouth."

thebigcow posted:

Group-Object seems to cram all the details of what was grouped as an object of a "Group" property. If you pipe that through
code:
 Select-Object -ExpandProperty "Group"
does that get you something usable?

Yes! Here's the new Snippet:

PowerShell code:

import-csv $RecordPath | Group-Object CurrentGroup, ApplicationType, CurrentHole, LaserLocation, LoginName, LastCommTime, DisconnectCount | Where-Object -FilterScript {$_.count -ge 5} | Select-Object -ExpandProperty Group | Export-Csv $DataPathAlertPotential -NoTypeInformation

The Output file:



So, I wrote this last part that does what I want but it would Populate the other values.

code:
Import-Csv $DataPathAlertPotential| Group-Object ApplicationType, CurrentHole, LaserLocation, CurrentHole, LoginName -NoElement | Sort-Object Count | Format-Table  ApplicationType, CurrentHole, LaserLocation, CurrentHole, Count, LoginName 
Output:


How do I get this table to fill in those missing values?



Modulo16 fucked around with this message at 16:14 on Jul 28, 2017

thebigcow
Jan 3, 2001

Bully!
Imgur gave you an album link instead of the picture itself.



I'll look again when I have some time.

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum
You can get Group-Object to output just the number of times each row shows up, and you can get Select-Object -Unique to output just the unique rows, and it would be really helpful if you could take those two arrays and add them, but PowerShell doesn't work like that, as far as I know. Unless you want to reconsider what you're trying to accomplish, the best suggestion I can give you is to send the Group-Object and Select-Object arrays to temporary variables, add a Count column to it, do a for loop on the Select-Object array, and insert the Count value from the Group-Object array on each line. With luck, the rows will even match!

anthonypants fucked around with this message at 22:30 on Jul 28, 2017

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

anthonypants posted:

You can get Group-Object[/fixed to output just the number of times each row shows up, and you can get [fixed]Select-Object -Unique to output just the unique rows, and it would be really helpful if you could take those two arrays and add them, but PowerShell doesn't work like that, as far as I know. Unless you want to reconsider what you're trying to accomplish, the best suggestion I can give you is to send the Group-Object and Select-Object arrays to temporary variables, add a Count column to it, do a for loop on the Select-Object array, and insert the Count value from the Group-Object array on each line. With luck, the rows will even match!

I'm having a hard time following the original question, but isn't what you described the same as doing this?

code:
$stuff | Group-Object -Property UniqueThing | ForEach-Object -Process { $_.Group[0] | Add-Member -NotePropertyName DupCount -NotePropertyValue $_.Count -Force -PassThru }
I don't think temporary variables are needed..

The key thing to remember is that Group-Object is working on some property, so the rows may not actually be unique; you have to be sure to choose a property (column) that accurately reflects the uniqutitude of the row.

The Fool
Oct 16, 2003


I'm doing some work with CSOM and needed to take a break to mention how awesome VS Code and the Powershell extension are.

Really starting to flex the VS Code debugger with this project.

Collateral Damage
Jun 13, 2009

VS Code is amazing. One of the best products that flew under the radar from Microsoft in recent years.

The Fool
Oct 16, 2003


code:
$creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($userID, $password)
$context = New-Object Microsoft.SharePoint.Client.ClientContext($siteURL)
$context.credentials = $creds
$web = $context.Web

$requestList = $web.Lists.GetByTitle("Matrix Requests")

$matrixRequest = $requestList.GetItemById($requestID)
$context.load($matrixRequest)
$context.executeQuery()

$spoUser = $web.EnsureUser($newPersonEmail)
$context.load($spoUser)
$context.ExecuteQuery()

$matrixRequest["hkye"] = $spoUser
$matrixRequest["dfep"] = $newTask
$matrixRequest.Update()
$context.load($matrixRequest)
$context.executeQuery()

:psypop:

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

Collateral Damage posted:

VS Code is amazing. One of the best products that flew under the radar from Microsoft in recent years.
vs code is now the official PowerShell IDE going forward :)

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy
NYC PowerShell Meetup tonight!

Irritated Goat
Mar 12, 2005

This post is pathetic.
Ok. Help me believe I'm not insane.

I'm using the NTFSSecurity module to assign Domain Users permissions to a folder.

code:
Import-Module NTFSSecurity
New-Item -type directory -path <local location for app>
Copy-Item <network location of app> <local location of app>
Get-item .\App | Add-NTFSAccess -Account "Domain\Domain Users" -AccessRights Modify
When it hits the Add-NTFSAccess portion, I get an access denied. I'm local admin on this PC so I'm confused as to why I'd even run into this issue. :confused:

The script basically just
    creates a folder
    copies the network install of it to the newly created folder
    Gives domain\domain users modify access on it as the application auto-updates itself

Pile Of Garbage
May 28, 2007



Irritated Goat posted:

Ok. Help me believe I'm not insane.

I'm using the NTFSSecurity module to assign Domain Users permissions to a folder.

code:
Import-Module NTFSSecurity
New-Item -type directory -path <local location for app>
Copy-Item <network location of app> <local location of app>
Get-item .\App | Add-NTFSAccess -Account "Domain\Domain Users" -AccessRights Modify
When it hits the Add-NTFSAccess portion, I get an access denied. I'm local admin on this PC so I'm confused as to why I'd even run into this issue. :confused:

The script basically just
    creates a folder
    copies the network install of it to the newly created folder
    Gives domain\domain users modify access on it as the application auto-updates itself

I'm not 100% familiar with that module but I suspect that the Add-NTFSAccess cmdlet doesn't accept pipeline input (Which is lovely design...). You'll probably just have to use the -Path parameter with either the full-path as a string or use Get-Item:

code:
Add-NTFSAccess -Path (Get-item .\App).FullName -Account "Domain\Domain Users" -AccessRights Modify
Edit: Just noticed that you are referencing the path with the relative .\ notation. That will resolve from whatever $PWD is (Usually working directory) and it's best not to use relative paths in a script as it will be inconsistent. I'd go with something similar to this:

code:
Import-Module NTFSSecurity
$Folder = New-Item -type directory -path <local location for app>
Copy-Item <network location of app> $Folder.FullName
Add-NTFSAccess -Path $Folder.FullName -Account "Domain\Domain Users" -AccessRights Modify

Pile Of Garbage fucked around with this message at 16:38 on Aug 29, 2017

Irritated Goat
Mar 12, 2005

This post is pathetic.

cheese-cube posted:


Edit: Just noticed that you are referencing the path with the relative .\ notation. That will resolve from whatever $PWD is (Usually working directory) and it's best not to use relative paths in a script as it will be inconsistent. I'd go with something similar to this:

code:
Import-Module NTFSSecurity
$Folder = New-Item -type directory -path <local location for app>
Copy-Item <network location of app> $Folder.FullName
Add-NTFSAccess -Path $Folder.FullName -Account "Domain\Domain Users" -AccessRights Modify

I'm still getting Access Denied issues. I'm beginning to wonder if there's not really a good way to add rights to a folder via script.

The Claptain
May 11, 2014

Grimey Drawer
Are you running an elevated Powershell? Also you may not have appropriate permissions on objects, even as an administrator on the machine, so you may need to first take ownership and grant yourself appropriate permissions.

Pile Of Garbage
May 28, 2007



The Claptain posted:

Are you running an elevated Powershell? Also you may not have appropriate permissions on objects, even as an administrator on the machine, so you may need to first take ownership and grant yourself appropriate permissions.

This is a good point. Are you running the script in the context of a local user or a domain user? A local user would not be able to resolve domain objects like the Domain Users group.

Also what version of PS are you using? Can you just use the native Get-Acl and Set-Acl cmdlets?

nielsm
Jun 1, 2009



cheese-cube posted:

Also what version of PS are you using? Can you just use the native Get-Acl and Set-Acl cmdlets?

I think the point is that constructing an ACL manually for use with Set-Acl is somewhat difficult.

Pile Of Garbage
May 28, 2007



To come back to the original question, if you need to allow Domain Users permission to modify the location then why don't you just copy the relevant files to somewhere like $env:PUBLIC or a similar location where users can write to by default? Relying on permission inheritance is always simpler than explicitly defining permissions. I'm assuming that you're attempting to copy something to local machines, correct?

Bunni-kat
May 25, 2010

Service Desk B-b-bunny...
How can-ca-caaaaan I
help-p-p-p you?
So I've gotten a bit better at this stuff, and now I want to expand my most-used script.

I've got one that I use for setting AD users to disabled and change the description to the ticket number associated and the date. I want to expand this in two ways.

1. I also want to move the users to our disabled OU.

2. I would like the script to ask me for the User's ID, and the ticket number.
My current script is
code:
set-aduser -identity USERID -Enabled 0 -Description "Disabled $(Get-Date): Disable account check, SDEXXXXXX"
And I've been modifying the script directly each time. Way too slow for my liking. I know it's possible to have a script ask you for inputs, I just can't figure out how.

I got this bit of code from ADAC:
code:
Move-ADObject -identity "CN=User Name,OU=Standard,OU=Users,OU=Contoso,DC=Foo,DC=Contoso,DC=ca" -Server:"DC-A101.Foo.Contoso.ca" -TargetPath:"OU=Disabled,OU=Standard,OU=Users,OU=Contoso,DC=Foo,DC=Contoso,DC=ca"
that was autogenerated when moving users manually, however when I try and run it through powershell, it doesn't move the user. No error thrown.

So is there a way to pipe the identity from set-aduser to move-adobject? I tried just doing | after filling out the set-aduser part manually, and the object didn't move. But that could be because my move script is non-functional.

Thoughts?

Inspector_666
Oct 7, 2003

benny with the good hair
In my user termination script, I have a variable $findUser that's just the result of

code:
Get-ADUser -filter { samaccountname -eq $usrName }
(Obviously adjust the filter depending on how you're doing it.)

Then to move them into the Disabled User Accounts OU is:

code:
Get-ADObject -Identity $findUser | Move-ADObject -TargetPath "OU=Disabled User Accounts,DC=corp,DC=contoso,DC=com"
...and it's worked without issue.

I think that you might be over-defining the identity in the example line you posted, but piping the object from Get-ADObject works.

EDIT: I use the $findUser variable elsewhere in the script (removing from groups, disabling, password reset, etc), it's a good kind of "catch-all" for the AD identity for everything I need to do.

Inspector_666 fucked around with this message at 20:34 on Aug 29, 2017

Irritated Goat
Mar 12, 2005

This post is pathetic.

cheese-cube posted:

To come back to the original question, if you need to allow Domain Users permission to modify the location then why don't you just copy the relevant files to somewhere like $env:PUBLIC or a similar location where users can write to by default? Relying on permission inheritance is always simpler than explicitly defining permissions. I'm assuming that you're attempting to copy something to local machines, correct?

Basically, it's an application that auto-downloads\updates itself on each run. If we plan to take away local admin from Domain Users, we need to make sure this can update on its own. I'm running it as a domain user with local admin rights currently, If that helps any.

cheese-cube posted:

This is a good point. Are you running the script in the context of a local user or a domain user? A local user would not be able to resolve domain objects like the Domain Users group.

Also what version of PS are you using? Can you just use the native Get-Acl and Set-Acl cmdlets?

I'm running 5.1 currently. I can run native Get\Set ACL but crafting that is a bit out of my depth right now.

nielsm
Jun 1, 2009



Avenging_Mikon posted:

2. I would like the script to ask me for the User's ID, and the ticket number.

The best approach (IMO) is to declare these as parameters, that way you can also call your script as part of another script, with the "host script" supplying the values instead of being locked in to interactive prompting.

I assume your script is a .ps1 file you run by itself. Put this block at the very top:
code:
param(
  $UserID = $null,
  $TicketID = $null
)

if (-not $UserID) {
  $userID = Read-Host "Enter user ID to disable"
}

if (-not $TicketID) {
  $ticketID = Read-Host "Enter work order ticket ID"
}
This declares that your script takes two parameters named -UserID and -TicketID (when you call it), and the code following the param() block checks if either value is falsy (e.g. null or empty) and prompts for a value from the user. The = $null part in the declaration says that if you don't specify the parameter, it gets a default value of $null.
You can do a lot more with parameters, but this is the most basic. Read up on the param() block as well as on the Read-Host cmdlet.

This way you can both call your script as "interactive" (e.g. right-click in File Explorer and choose Run, or click the Run button in the ISE), or you can call it with parameters from the prompt, like:
.\DisableUser.ps1 -UserID fred -TicketID SDE0023523

nielsm fucked around with this message at 21:22 on Aug 29, 2017

Mo_Steel
Mar 7, 2008

Let's Clock Into The Sunset Together

Fun Shoe

nielsm posted:

The best approach (IMO) is to declare these as parameters, that way you can also call your script as part of another script, with the "host script" supplying the values instead of being locked in to interactive prompting.

I assume your script is a .ps1 file you run by itself. Put this block at the very top:
code:
param(
  $UserID = $null,
  $TicketID = $null
)

if (-not $UserID) {
  $userID = Read-Host "Enter user ID to disable"
}

if (-not $TicketID) {
  $ticketID = Read-Host "Enter work order ticket ID"
}
This declares that your script takes two parameters named -UserID and -TicketID (when you call it), and the code following the param() block checks if either value is falsy (e.g. null or empty) and prompts for a value from the user. The = $null part in the declaration says that if you don't specify the parameter, it gets a default value of $null.
You can do a lot more with parameters, but this is the most basic. Read up on the param() block as well as on the Read-Host cmdlet.

This way you can both call your script as "interactive" (e.g. right-click in File Explorer and choose Run, or click the Run button in the ISE), or you can call it with parameters from the prompt, like:
.\DisableUser.ps1 -UserID fred -TicketID SDE0023523

This is also what I do; you can specify the type of the parameter as well as whether it's mandatory or not, which is really useful. Going to second the suggestion on Read-Host too; I'm a big fan of confirmations in scripts I'm only running manually, so this sort of block is really useful:

code:
$continue = Read-Host "Are you sure you want to disable $userID ? (Y/N)"
If($continue -eq "y"){
	# Code to disable users goes here
}
Else {
	"Script aborted by user"
	exit
}
Always good to double-check that you didn't typo a filename or user and avoid wiping a whole directory out or resetting the password on the wrong user account.

Pile Of Garbage
May 28, 2007



Just to expand on interactive confirmation prompts do/while loop is handy to ensure you get a desired response:

code:
do { $Continue = Read-Host -Prompt "Are you sure you want to disable $userID? (Y/N)" } while ($Continue -ne 'y' -and $Continue -ne 'n')

Dr. Arbitrary
Mar 15, 2006

Bleak Gremlin
I think I'm missing something important when it comes to credentials and permissions.

I need to use Get-Certificate to request computer account certificates on a huge number of remote machines. It works fine when I RDP in, run Powershell as an administrator, and then run the command.

I need to do something equivalent to that while connecting via Invoke-Command or Enter-PSSession.

There has to be a way to do this, right?

thebigcow
Jan 3, 2001

Bully!
Sounds like the PowerShell double hop problem. Maybe this will help: https://blogs.technet.microsoft.com/ashleymcglone/2016/08/30/powershell-remoting-kerberos-double-hop-solved-securely/

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum
I want to run an updater on an application, but it's for Mozilla Firefox so the steps involved are incredibly convoluted and stupid and I hate it. It pushes the status of the updater process to a file, which is just a single word, like "applying" or "failed" or "succeeded". I also don't know how long it's going to take. Would something like do {Start-Sleep -s 60} until (Get-Content "\\path\to\update.status" = "succeeded") in a script do what I think it will?

The Fool
Oct 16, 2003


anthonypants posted:

I want to run an updater on an application, but it's for Mozilla Firefox so the steps involved are incredibly convoluted and stupid and I hate it. It pushes the status of the updater process to a file, which is just a single word, like "applying" or "failed" or "succeeded". I also don't know how long it's going to take. Would something like do {Start-Sleep -s 60} until (Get-Content "\\path\to\update.status" = "succeeded") in a script do what I think it will?

((get-content "\\path\to\update.status") -eq "succeeded")

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

The Fool posted:

((get-content "\\path\to\update.status") -eq "succeeded")
What I would like is for the script to hold up and not perform any of the post-install junk. I don't think that's going to do that.

The Fool
Oct 16, 2003


anthonypants posted:

What I would like is for the script to hold up and not perform any of the post-install junk. I don't think that's going to do that.

It will if you put use the do..until as you wrote it, I just corrected your conditional.

code:
Do {Start-Sleep -s 3} until (("get-content c:\users\the fool\Documents\Scripts\test.txt") -eq "false"); Write-Host "Exiting."
Where test.txt is a single line file. The loop exits when the file is set to the single word "false"

Works as you would expect

The Fool fucked around with this message at 00:38 on Sep 23, 2017

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

The Fool posted:

It will if you put use the do..until as you wrote it, I just corrected your conditional.

code:
Do {Start-Sleep -s 3} until (("get-content c:\users\the fool\Documents\Scripts\test.txt") -eq "false"); Write-Host "Exiting."
Where test.txt is a single line file. The loop exits when the file is set to the single word "false"

Works as you would expect
buhh, I just realized I did an = instead of an -eq

Adbot
ADBOT LOVES YOU

mystes
May 31, 2006

anthonypants posted:

buhh, I just realized I did an = instead of an -eq
I have done that so many times in powershell.

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