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
thebigcow
Jan 3, 2001

Bully!
Start reading. http://ss64.com/nt/robocopy.html

Adbot
ADBOT LOVES YOU

Pile Of Garbage
May 28, 2007



Moundgarden posted:

It performs like absolute garbage, presumably because of the triple wildcard in the filepath and all the sorting I need to do. I couldn't find a way around that, and unfortunately I have no power to modify the folder structure. Any tips on optimizing something like this or am I pretty much SOL?

Get-ChildItem is notoriously slow, especially when working recursively with a large amount of files/folders: https://blogs.msdn.microsoft.com/powershell/2009/11/04/why-is-get-childitem-so-slow/

So yeah, Robocopy.

CLAM DOWN
Feb 13, 2007




I'm trying to figure out a way in PS (version 5) to read the metadata of a file, for example an image file, reading the EXIF data stored in it. When you go to the details tab of the file properties and see something like the camera used, that's the kind of label I want to read. Get-ItemProperty shows the properties, attributes, timestamps, etc, but I don't know how to query in on the other values. Any ideas?

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

CLAM DOWN posted:

I'm trying to figure out a way in PS (version 5) to read the metadata of a file, for example an image file, reading the EXIF data stored in it. When you go to the details tab of the file properties and see something like the camera used, that's the kind of label I want to read. Get-ItemProperty shows the properties, attributes, timestamps, etc, but I don't know how to query in on the other values. Any ideas?
Google suggests that you should use COM :getin:

CLAM DOWN
Feb 13, 2007




Uggggh COM objects. Yeah, I found something simliar to what I want to do here: http://mickitblog.blogspot.ca/2016/07/powershell-retrieving-file-details.html

Ugggggggggggggh

Pile Of Garbage
May 28, 2007



CLAM DOWN posted:

Uggggh COM objects. Yeah, I found something simliar to what I want to do here: http://mickitblog.blogspot.ca/2016/07/powershell-retrieving-file-details.html

Ugggggggggggggh

You can use the FromFile(String) method of the System.Drawing.Image class to retrieve the metadata of an image file. Unfortunately it's not exactly easy to parse as the values are either integers or byte arrays. This article provides some info about how to parse it: https://msdn.microsoft.com/en-us/library/xddt0dz7(v=vs.110).aspx.

It's still possible though. Using the info in that article I wrote this snippet that retrieves the value of the Equipment Manufacturer property item (ID 271 or 0x010F) from an image and then converts it to a string (The property has a type of 2 which indicates that it's a byte array of ASCII encoded text):

code:
$EncodingObject = New-Object -TypeName System.Text.ASCIIEncoding
$Manufacturer = ([System.Drawing.Image]::FromFile('C:\Temp\farts.jpg')).PropertyItems | Where-Object -FilterScript { $_.Id -eq 271 }
$Encoding.GetString($Manufacturer.Value)
This article lists the IDs of the metadata property tags: https://msdn.microsoft.com/en-us/library/system.drawing.imaging.propertyitem.id(v=vs.110).aspx. Using the IDs and the property types you should be able to decode the majority of the metadata but yeah, kinda annoying.

Pile Of Garbage fucked around with this message at 00:48 on Oct 5, 2016

Cpt.Wacky
Apr 17, 2005
I'm working with Windows 7 and Powershell 2. I have a tab-separated value file that uses CR line endings instead of LF or CR/LF and Import-CSV isn't working. It doesn't seem to read and return anything, and doesn't produce any warnings or errors.

This file comes from a state web app, with a button called SaveToXLS which produces this tab-separated values file with old Mac-style CR line endings and an XLS extension. :negative:

Can I fix the line endings in Powershell 2? Or does Import-CSV support CR line endings in a later version? I can always just convert the line endings manually but I'd like to avoid any manual steps possible since the whole point of this project is to automate things...

For extra points, the fields are all wrapped in ="<data>" and I'd like to remove those characters too, but I can probably figure that out on my own.

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.

Dr. Arbitrary
Mar 15, 2006

Bleak Gremlin

Cpt.Wacky posted:

I'm working with Windows 7 and Powershell 2. I have a tab-separated value file that uses CR line endings instead of LF or CR/LF and Import-CSV isn't working.

Are you using -delimiter "`t" for tabs?

If you had Powershell 3, it adds the -raw parameter
(Get-Content ".\file.csv" -raw).Replace("`n","`r`n")

Not sure if there's a workaround using .net or something.

Edit:

[System.IO.File]::ReadAllText(".\file.csv")

I think that's what you want.

Edit2: how big are the files. I think there's a stream version of IO stuff that would be much faster.

Dr. Arbitrary fucked around with this message at 02:06 on Oct 6, 2016

Cpt.Wacky
Apr 17, 2005

Mario posted:

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.

That does work. I had a similar idea overnight as I had already started using Get-Content to parse the data myself and it was handling the CR line endings correctly.

Dr. Arbitrary posted:

Are you using -delimiter "`t" for tabs?

Edit:

[System.IO.File]::ReadAllText(".\file.csv")

I think that's what you want.

Edit2: how big are the files. I think there's a stream version of IO stuff that would be much faster.

Yes, I'm using the tab delimiter. The files are ~100 lines so speed isn't much of an issue.

Now that I'm able to import the CSV I get this type of data:
code:
="Name"         : ="Dude, The"
="Domain Name"  : ="12345678"
="Organization" : ="Widget House"
="Status"       : ="Approved"
="Start Date"   : ="07/05/2016"
="End Date"     : ="12/31/2999"
="RNM"          : ="1"
It feels like it would be easier to read the file in and remove the ="..." from everything, then pass it to ConvertFrom-CSV, or is there an easy way to strip that stuff after it's already in this data structure?

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

Cpt.Wacky posted:

That does work. I had a similar idea overnight as I had already started using Get-Content to parse the data myself and it was handling the CR line endings correctly.


Yes, I'm using the tab delimiter. The files are ~100 lines so speed isn't much of an issue.

Now that I'm able to import the CSV I get this type of data:
code:
="Name"         : ="Dude, The"
="Domain Name"  : ="12345678"
="Organization" : ="Widget House"
="Status"       : ="Approved"
="Start Date"   : ="07/05/2016"
="End Date"     : ="12/31/2999"
="RNM"          : ="1"
It feels like it would be easier to read the file in and remove the ="..." from everything, then pass it to ConvertFrom-CSV, or is there an easy way to strip that stuff after it's already in this data structure?
Does v2 not have Import-Csv? Does the actual .csv text contain text like ="Name",="Dude, The"?

anthonypants fucked around with this message at 19:05 on Oct 6, 2016

Cpt.Wacky
Apr 17, 2005

anthonypants posted:

Does v2 not have Import-Csv? Does the actual .csv text contain text like ="Name",="Dude, The"?

Import-CSV in v2 doesn't handle the CR line endings correctly. This is what I'm reading in:
code:
="Name"<TAB>="Domain Name"<TAB>="Organization"<TAB>="Status"<TAB>="Start Date"<TAB>="End Date"<TAB>="RNM"<CR>
="Dude, The "<TAB>="12345678"<TAB>="Widget House"<TAB>="Approved"<TAB>="07/05/2016"<TAB>="12/31/2999"<TAB>="1"<CR>

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

Cpt.Wacky posted:

Import-CSV in v2 doesn't handle the CR line endings correctly. This is what I'm reading in:
code:
="Name"<TAB>="Domain Name"<TAB>="Organization"<TAB>="Status"<TAB>="Start Date"<TAB>="End Date"<TAB>="RNM"<CR>
="Dude, The "<TAB>="12345678"<TAB>="Widget House"<TAB>="Approved"<TAB>="07/05/2016"<TAB>="12/31/2999"<TAB>="1"<CR>
What character is the <CR> in your file? It might be easier to replace that character with one Import-Csv likes. Also, can you set the delimiter to '`t='?

Dr. Arbitrary
Mar 15, 2006

Bleak Gremlin

anthonypants posted:

What character is the <CR> in your file? It might be easier to replace that character with one Import-Csv likes. Also, can you set the delimiter to '`t='?

v2 doesn't have get-content -raw

So you have to use the thingie I posted earlier.

Cpt.Wacky
Apr 17, 2005

anthonypants posted:

What character is the <CR> in your file? It might be easier to replace that character with one Import-Csv likes. Also, can you set the delimiter to '`t='?

It's a carriage return, decimal byte 13, hex 0x0D. ConvertFrom-CSV doesn't like "`t=", saying it must be exactly one character long.

It looks like this is what I needed:
code:
(Get-Content providerone.csv) -replace '="', '' -replace '"', '' | ConvertFrom-CSV -Delimiter "`t"
Thanks for the help!

MC Fruit Stripe
Nov 26, 2002

around and around we go
I'm scripting out some service cycling, and I need to do it in a specific order. I'm trying to put together a script to essentially bring down an environment gracefully - a process which normally involves myself, another sys admin, or someone from operations clicking like a madman for 15 minutes with half a dozen service dependencies in mind. Service A has to be started before service B, don't stop B if C is still running, and so forth. We're looking at probably 25 services, maybe half with dependencies I want to address, so being able to cycle these in a specified order would be great.

So for stopping or for starting, the script is almost identical

code:
$servers = Get-Content -Path "c:\stripe\servers.txt"
$services = Get-Content -Path "c:\stripe\stopservices.txt"
Get-Service -Name $services -ComputerName $servers | Set-Service -Status Stopped

$servers = Get-Content -Path "c:\stripe\servers.txt"
$services = Get-Content -Path "c:\stripe\startservices.txt"
Get-Service -Name $services -ComputerName $servers | Set-Service -Status Running
However, when it grabs that list of services, regardless of the order they're placed into the text file, it alphabetizes them and goes in that order. Service A, B, C, D. In the file, I have them in order C, B, A, D and would like the services cycled in that order.

Given what I'm trying to accomplish, is there an approach which doesn't involve 372 nested foreach loops here?

Dr. Arbitrary
Mar 15, 2006

Bleak Gremlin
Do you have Powershell 3?

pre:
$a = [ordered]@{a=1;b=2;d=3;c=4}
Otherwise, create a custom PSObject with two parameters, the sequence number and the servername and have it do them in order by sequence.

MC Fruit Stripe
Nov 26, 2002

around and around we go
When using ordered in this case, I'd need to specify every service in the script itself and not in a text file, no? I don't see a way to use both, essentially a $services = [ordered]stopservices.txt approach. Placing the services directly into the script, essentially going from

code:
$servers = Get-Content -Path "c:\stripe\servers.txt"
$services = Get-Content -Path "c:\stripe\stopservices.txt"
Get-Service -Name $services -ComputerName $servers | Set-Service -Status Stopped
to

code:
$servers = Get-Content -Path "c:\stripe\servers.txt"
$services = [ordered]@{"DHCP Client"=1;"Task Scheduler"=2;"IPsec Policy Agent"=3;"Base Filtering Engine"=4}
Get-Service -Name $services -ComputerName $servers | Set-Service -Status Stopped
Given these scripts, would

Script 1 stopping in order: Base Filtering Engine, DHCP Client, IPsec Policy Agent, Task Scheduler
Script 2 stopping in order: DHCP Client, Task Scheduler, IPsec Policy Agent, Base Filtering Engine

Would that be right?

Edit: Heh, you know what, this whole thing may be pointless. There is absolutely no reason to do this, and I mean I appreciate a good learning opportunity as much as the next guy, but this is a straight up copy paste situation. Forest for the trees, missed the drat forest for the trees.

code:
$servers = Get-Content -Path "c:\stripe\servers.txt"
Get-Service -Name "Not a Real Service" -ComputerName $servers | Set-Service -Status Stopped (throws an error quickly and moves on to...)
Get-Service -Name "DHCP Client" -ComputerName $servers | Set-Service -Status Stopped
Get-Service -Name "Task Scheduler" -ComputerName $servers | Set-Service -Status Stopped
Tested, worked, probably as complicated as I need to make that one no?

MC Fruit Stripe fucked around with this message at 05:30 on Oct 11, 2016

sloshmonger
Mar 21, 2013

MC Fruit Stripe posted:

When using ordered in this case, I'd need to specify every service in the script itself and not in a text file, no? I don't see a way to use both, essentially a $services = [ordered]stopservices.txt approach. Placing the services directly into the script, essentially going from

code:
$servers = Get-Content -Path "c:\stripe\servers.txt"
$services = Get-Content -Path "c:\stripe\stopservices.txt"
Get-Service -Name $services -ComputerName $servers | Set-Service -Status Stopped
to

code:
$servers = Get-Content -Path "c:\stripe\servers.txt"
$services = [ordered]@{"DHCP Client"=1;"Task Scheduler"=2;"IPsec Policy Agent"=3;"Base Filtering Engine"=4}
Get-Service -Name $services -ComputerName $servers | Set-Service -Status Stopped
Given these scripts, would

Script 1 stopping in order: Base Filtering Engine, DHCP Client, IPsec Policy Agent, Task Scheduler
Script 2 stopping in order: DHCP Client, Task Scheduler, IPsec Policy Agent, Base Filtering Engine

Would that be right?

Edit: Heh, you know what, this whole thing may be pointless. There is absolutely no reason to do this, and I mean I appreciate a good learning opportunity as much as the next guy, but this is a straight up copy paste situation. Forest for the trees, missed the drat forest for the trees.

code:
$servers = Get-Content -Path "c:\stripe\servers.txt"
Get-Service -Name "Not a Real Service" -ComputerName $servers | Set-Service -Status Stopped (throws an error quickly and moves on to...)
Get-Service -Name "DHCP Client" -ComputerName $servers | Set-Service -Status Stopped
Get-Service -Name "Task Scheduler" -ComputerName $servers | Set-Service -Status Stopped
Tested, worked, probably as complicated as I need to make that one no?

Sounds like you have that one pretty much solved, but could you use import-csv instead of get-content, as import-csv preserves ordering?

lol internet.
Sep 4, 2007
the internet makes you stupid
Question and advice needed about powershell!

Question - How come the PSSnappin command is used for some things instead of import-module? Is there really any difference between these?


Advice - I have 3 web servers. During a DR scenario, one or two of them might be offline. I am looking to create a powershell script which is on a monitoring server that will attempt to connect to any of the servers and execute a powershell script either stored locally on the servers or remotely. The script itself only needs to be executed on any one server that is up, not on every server that is up. What would be the best way to go about this? Just looking for a general direction.

Roargasm
Oct 21, 2010

Hate to sound sleazy
But tease me
I don't want it if it's that easy

lol internet. posted:



Question - How come the PSSnappin command is used for some things instead of import-module? Is there really any difference between these?

Advice - I have 3 web servers. During a DR scenario, one or two of them might be offline. I am looking to create a powershell script which is on a monitoring server that will attempt to connect to any of the servers and execute a powershell script either stored locally on the servers or remotely. The script itself only needs to be executed on any one server that is up, not on every server that is up. What would be the best way to go about this? Just looking for a general direction.

Snapins were deprecated in favor of modules sometime between v2 and v3.

For your second thing you can use
if (test-path \\server01\share) {run script}
elseif (test-path \\server02\share) {run script}
elseif (test-path \\server03\share) {run script}
else {echo "gently caress" > c:\failed.log}

Anyone do any recursion? I like nice looking code as much as the next guy but I'm golfing for a 1 liner to print enabled users and subgroups from a given AD group and ideally want to pipe the subgroups back into the original query and enumerate those too

Import-module activedirectory; get-adgroupmember 'esx admins' | where {$_.objectclass -eq 'group' -or ($_.objectclass -eq 'user' -and ((get-aduser $_.samaccountname).Enabled -eq 'True')) } | select samaccountname, name, distinguishedname, objectclass | ft -auto

Roargasm fucked around with this message at 15:59 on Oct 13, 2016

lol internet.
Sep 4, 2007
the internet makes you stupid
Thank you! Didn't realize test-path worked on UNC paths but when you think about it I guess why wouldn't it.

kaynorr
Dec 31, 2003

Roargasm posted:

Anyone do any recursion? I like nice looking code as much as the next guy but I'm golfing for a 1 liner to print enabled users and subgroups from a given AD group and ideally want to pipe the subgroups back into the original query and enumerate those too

I recently implemented a recursive algorithm in PowerShell for the first time and didn't run into any problems. Just keep in mind all the usual CS 101 stuff about recursions (head/tail, putting in breaks against infinite loops) because otherwise you'll have to kill a LOT of PoweShellISE.exe processes.

Eschatos
Apr 10, 2013


pictured: Big Cum's Most Monstrous Ambassador

sloshmonger posted:

I've pretty much already done 3 & 4 in a script that was supposed to step through all subnet IPs and inventory them.

If you can figure out how to get the info from either the registry or WMIC you can easily extract it. It may require PS v5.

scrip

Yes, it's pretty crappy, but it does its job. If i had to change anything I'd make it so that the processing is done on the remote side, rather than on the local computer.

Forgot to say this earlier, but thanks! I'm trying to implement it by querying AD names instead of IP addresses but the overall structure has been real helpful so far.

Also, saw this on r/powershell and it's fantastic for trolling the other members of my department.

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum
If you think that's great then you need to check out cheese-cube's post on the previous page.

Eschatos
Apr 10, 2013


pictured: Big Cum's Most Monstrous Ambassador

anthonypants posted:

If you think that's great then you need to check out cheese-cube's post on the previous page.

Ooh, nice. Just need to figure out how to run it remotely. Invoke-command doesn't do the trick.

Pile Of Garbage
May 28, 2007



Just want to note that the only reason I Base64 encoded the URL was so that I could post it on Twitter and avoid their auto URL parser.

Also if you really want to be an rear end in a top hat you can render their computer unusable with this:

code:
do{iex $env:SystemRoot\System32\Bubbles.scr}while($true)
All it does is continuously launches the Bubbles screensaver. The kicker is that the screensaver captures all mouse/keyboard input when running so you can't even get Ctrl+Alt+Del in and will have to hard-reset. Should work on all versions of Windows but only tested on 7 and 10.

Edit: I guess they could kill the powershell.exe process remotely...

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum
I wanted a script to get the second-to-last day of the month, so I took this script and modified it.
code:
Function Get-XOfMonth {
<#

.SYNOPSIS
Get certain days of the month.

.DESCRIPTION
This script is used to find the first, second, last, etc. calendar day of the
month, given a day of the week and the order, based on the numerical index
starting at zero ('0'). If you want to count from the last day of the month,
use '-1' for the last day, '-2' for the next-to-last day, and so on.
You may use the Month or Year parameters to select a month or year in the past
or future.
You may use the asDate flag to output the entire date string as opposed to the
day of the month. This output is a DateTime object, which may be modified with
DateTime methods or used in any other command which takes DateTime input.


.EXAMPLE
PS C:\> Get-XOfMonth -Day Friday -Month 10 -Year 2016 -asDate -Count -1

Friday, October 28, 2016 2:29:14 PM


.NOTES
Massive thanks to Emin Atac at the p0w3rsh3ll Wordpress blog. They clearly
know way more about PowerShell than I do, but I made a few changes.

.LINK
[url]https://p0w3rsh3ll.wordpress.com/2012/10/26/finding-the-last-sunday-or-another-day-of-a-month/[/url]

#>
[CmdletBinding()]
param(
    [parameter(Mandatory)]
    [ValidateSet('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')]
    [String]$Day,

    [parameter(ParameterSetName='ByDate',Mandatory,ValueFromPipeline)]
    [System.DateTime]$Date,

    [parameter(ParameterSetName='ByString',ValueFromPipelineByPropertyName)]
    [ValidateRange(1,12)]
    [int]$Month,
    [parameter(ParameterSetName='ByString',ValueFromPipelineByPropertyName)]
    [ValidatePattern('^\d{4}$')]
    [int]$Year,

    [switch]$asDate=$false,

    [parameter(ParameterSetName='ByString',Mandatory,ValueFromPipelineByPropertyName)]
    [ValidateRange(-5,5)]
    [int]$Count
)
Begin {
    $alldays = @()
}
Process {
    if ($Month -eq '') {
        $Month = Get-Date -Format MM
    }
    
    if ($Year -eq '') {
        $Year = Get-Date -Format yyyy
    }
        
    Switch ($PSCmdlet.ParameterSetName) {
        ByString {
            # Do nothing, variables are already defined and validated
        }
        ByDate {
            $Month = $Date.Month
            $Year = $Date.Year
        }
    }
    # There aren't 32 days in any month so we make sure we iterate through all days in a month
    0..31 | ForEach-Object -Process {
        $evaldate = (Get-Date -Year $Year -Month $Month -Day 1).AddDays($_)
        if ($evaldate.Month -eq $Month) {
            if ($evaldate.DayOfWeek -eq $Day) {
                $alldays += $evaldate.Day
            }
        }
    }
    if ($alldays[$Count] -eq $null) {
        Write-Warning -Message "There is no '$Count' day of $(Get-Date -Month $Month -Format MMMM)."
        return
    }
    # Output
    if ($asDate) {
        Get-Date -Year $Year -Month $Month -Day $alldays[$Count]
    } else {
        $alldays[$Count]
    }
}
End {}
}

Pile Of Garbage
May 28, 2007



Good stuff. Minor optimisation, you could use the DateTime.DaysInMonth method and replace the ForEach-Object loop with a while loop (Who knows, maybe there will be a month with more than 32 days lol):

code:
$DayCounter = 0
do {
    $evaldate = (Get-Date -Year $Year -Month $Month -Day 1).AddDays($DayCounter)
    if ($evaldate.Month -eq $Month) {
        if ($evaldate.DayOfWeek -eq $Day) {
            $alldays += $evaldate.Day
        }
    }
    $DayCounter++
} while ($DayCounter -le [System.DateTime]::DaysInMonth($Year, $Month))
Speaking of scripts, I was trying to use this one from Microsoft recently however I found that it has no proxy server support: https://www.microsoft.com/en-us/download/details.aspx?id=46381. So I went and modified it so that a proxy server can be specified: http://pastebin.com/1JJXj7SP. Lines 64-66 and 493-505 have been added and line 176 has been modified. It uses the same strings.psd1 file and works like a charm! Oh, except for the fact that the modifications invalidate the signature so if your execution policy is set to RemoteSigned it probably won't run...

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

cheese-cube posted:

Good stuff. Minor optimisation, you could use the DateTime.DaysInMonth method and replace the ForEach-Object loop with a while loop (Who knows, maybe there will be a month with more than 32 days lol):

code:
$DayCounter = 0
do {
    $evaldate = (Get-Date -Year $Year -Month $Month -Day 1).AddDays($DayCounter)
    if ($evaldate.Month -eq $Month) {
        if ($evaldate.DayOfWeek -eq $Day) {
            $alldays += $evaldate.Day
        }
    }
    $DayCounter++
} while ($DayCounter -le [System.DateTime]::DaysInMonth($Year, $Month))
This is good, I completely ignored that whole block because it Just Works, and it runs fast enough so I didn't really care that the loop had to iterate at most 31 times. I also think it would also be nice to add a "[weekday] before/after" parameter, and I could definitely repurpose this.

mystes
May 31, 2006

Is there any way to create a function in the calling scope? For variables you can do stuff like set-variable -scope 1 but it seems like (at least on powershell 2 which is what I was using) there's no way to do this for functions. Not that this is a particularly good idea anyway, but I was bored and trying to work around the lack of first class function by messing with script blocks.

The Fool
Oct 16, 2003


I made some modifications to this code that allows a powershell script to trigger a uac prompt. Specifically, I've modified it so it can run as a function, and can run from a mapped network drive.

Call this function in a script that needs admin privileges, it will trigger a uac prompt, and the re-launch the script with the credentials you entered in the UAC prompt.

I don't know how useful this is to other people, but I'm getting some mileage out of it.

code:
function Prompt-UAC
{
  # Get the ID and security principal of the current user account
  $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
  $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)

  # Get the security principal for the Administrator role
  $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator

  # Check to see if we are currently running "as Administrator"
  if ($myWindowsPrincipal.IsInRole($adminRole))
    {
      Write-Host Elevated Powershell
    }
    else
    {
      # We are not running "as Administrator" - so relaunch as administrator

      # Create a new process object that starts PowerShell
      $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";

      # Specify the current script path and name as a parameter
      $scriptPath = $myInvocation.PSCommandPath;
      $driveLetter = Split-Path -qualifier $scriptPath;
      If (Is-Network($driveLetter)) {
        $logicalDisk = Gwmi Win32_LogicalDisk -filter "DriveType = 4 AND DeviceID = '$driveLetter'"
        $scriptPath = $scriptPath.Replace($driveLetter, $logicalDisk.ProviderName)
      }
      $newProcess.Arguments = $scriptPath;

      # Indicate that the process should be elevated
      $newProcess.Verb = "runas";

      # Start the new process
      [System.Diagnostics.Process]::Start($newProcess);

      # Exit from the current, unelevated, process
      exit

    }
}

Walked
Apr 14, 2003

Hey with PowerShell gallery modules- what does the x and c prefix denote? I can't find a definitive answer on Google and it's driving me mad

Pile Of Garbage
May 28, 2007



The Fool posted:

I made some modifications to this code that allows a powershell script to trigger a uac prompt. Specifically, I've modified it so it can run as a function, and can run from a mapped network drive.

Call this function in a script that needs admin privileges, it will trigger a uac prompt, and the re-launch the script with the credentials you entered in the UAC prompt.

I don't know how useful this is to other people, but I'm getting some mileage out of it.

Nice, this is useful. I was recently banging my head against the wall trying to get a script to elevate properly when run interactively from a batch file (I created it for helldesk people and wanted to pass it some set parameters). The bodge I came up with was using Start-Process with the RunAs verb:

code:
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "& {
 Start-Process -FilePath $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell.exe -ArgumentList '-File \\example.com\dfs_root\Script\Script.ps1 -Action foo -OtherAction bar' -Verb RunAs
}"

Walked posted:

Hey with PowerShell gallery modules- what does the x and c prefix denote? I can't find a definitive answer on Google and it's driving me mad

Not sure what you're referring to, can you provide an example?

hihifellow
Jun 17, 2005

seriously where the fuck did this genre come from

The Fool posted:

I made some modifications to this code that allows a powershell script to trigger a uac prompt. Specifically, I've modified it so it can run as a function, and can run from a mapped network drive.

Call this function in a script that needs admin privileges, it will trigger a uac prompt, and the re-launch the script with the credentials you entered in the UAC prompt.

I don't know how useful this is to other people, but I'm getting some mileage out of it.

I've always just stuck this on top of any script that needs to run as admin and might get used by the helpdesk.

code:
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
    $arguments = "& '" + $myinvocation.mycommand.definition + "'"
    Start-Process powershell -Verb runAs -ArgumentList $arguments
    Break
}

Walked
Apr 14, 2003

cheese-cube posted:


Not sure what you're referring to, can you provide an example?

Sorry missed this; but did manage to track down the info I was after.

xModuleName denotes "experimental"
cModuleName denotes "community provided"

I was trying to figure out what to release my module in the PS gallery as, naming-wise, and cModuleName was the way to go.

Venusy
Feb 21, 2007
Late, but...

sloshmonger posted:

I've pretty much already done 3 & 4 in a script that was supposed to step through all subnet IPs and inventory them.

If you can figure out how to get the info from either the registry or WMIC you can easily extract it. It may require PS v5.
...
Yes, it's pretty crappy, but it does its job. If i had to change anything I'd make it so that the processing is done on the remote side, rather than on the local computer.
Since I don't have PSRemoting enabled on most machines at work, the way I do this is with a DCOM CimSession rather than lots of WMI queries. PowerShell v3+ is required on your machine, but the hosts can be v2.
code:
$computername = Get-ADComputer -Filter * -SearchBase "OU=Whatever,DC=contoso,DC=com" | select -ExpandProperty Name
$option = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName $computername -SessionOption $option -ErrorVariable CIMError

$osjob = Get-CimInstance Win32_OperatingSystem -CimSession $session
$computerjob = Get-CimInstance Win32_ComputerSystem -CimSession $session
$biosjob = Get-CimInstance Win32_Bios -CimSession $session

foreach ($computer in $session.ComputerName) {
    $operatingsystem = $osjob | where PSComputerName -eq $computer
    $computersystem = $computerjob | where PSComputerName -eq $computer
    $bios = $biosjob | where PSComputerName -eq $computer

    $obj = [PSCustomObject]@{
        Name = $computersystem.Name
        Manufacturer = $computersystem.Manufacturer
        Model = $computersystem.Model
        UserName = $computersystem.UserName
        Serial = $bios.SerialNumber
        OS = $operatingsystem.Caption
        Version = $operatingsystem.Version
        InstallDate = $operatingsystem.InstallDate
        Architecture = $operatingsystem.OSArchitecture
        InstalledRAM = [int32]($computersystem.TotalPhysicalMemory / 1GB)
    }
    Write-Output $obj
}

$session | Remove-CimSession
The full version of this script is a function, so it has some error handling for stuff that shows up in $CIMError, and $ComputerName is given as a parameter instead of hardcoded - so I have a scheduled task that runs this against everything and chucks that out to Export-CSV, or I can just run it at the PS console against one (group of) machine(s).

milk milk lemonade
Jul 29, 2016
I'm writing a password reset script and I figured out how to get it to say "Sorry! That user doesn't exist" but I want it to return to the start of the script when that happens. Is there an easy way to do this? I've looked at a few things like erroraction but I don't think this applies when I do GetADUser and want it to either display the results or say "whoops!". If I need to start over and look at it from another angle I'd appreciate any tips on where to start!

edit: Sorry, forgot I wasn't using getADuser. This is what I'm using to return whether the account exists or not:

code:
if(dsquery user -samid $account){"Found User"}
else {"User Does Not Exist"}

milk milk lemonade fucked around with this message at 16:23 on Nov 1, 2016

Walked
Apr 14, 2003

milk milk lemonade posted:

I'm writing a password reset script and I figured out how to get it to say "Sorry! That user doesn't exist" but I want it to return to the start of the script when that happens. Is there an easy way to do this? I've looked at a few things like erroraction but I don't think this applies when I do GetADUser and want it to either display the results or say "whoops!". If I need to start over and look at it from another angle I'd appreciate any tips on where to start!

edit: Sorry, forgot I wasn't using getADuser. This is what I'm using to return whether the account exists or not:

code:
if(dsquery user -samid $account){"Found User"}
else {"User Does Not Exist"}

There's a lot of ways to handle this (relatively easily, too); can you post your full code of psuedo code, not just the if/else block

Adbot
ADBOT LOVES YOU

milk milk lemonade
Jul 29, 2016
Sure:

code:
$account = Read-Host -Prompt 'Input user account'

if(dsquery user -samid $account){"Found User"}
else {"User Does Not Exist"}

$password = Read-Host -AsSecureString "New Password"



Set-ADAccountPassword -Reset -Identity "$account" -NewPassword $password

Set-ADUser -Identity "$account" -ChangePasswordAtLogon 1 -Confirm

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