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
Glans Dillzig
Nov 23, 2011

:justpost::justpost::justpost::justpost::justpost::justpost::justpost::justpost:

knickerbocker expert

Jelmylicious posted:

:words:

Wicaeed posted:

:words:

Wow, holy crap, thanks a lot you guys. I'll definitely look into this and get it written. Now I have something to do at work, haha.

fake edit: page snyped. Hoo boy.

Adbot
ADBOT LOVES YOU

Wicaeed
Feb 8, 2005

adaz posted:

Ridiculously awesome stuff

Holy poo poo, so much useful information there :psypop:

Wait, I thought that variables not defined outside of a function can't exist outside it?

e.g. the difference between $global:variable and $variable, etc...

adaz
Mar 7, 2009

Wicaeed posted:

Holy poo poo, so much useful information there :psypop:

Wait, I thought that variables not defined outside of a function can't exist outside it?

e.g. the difference between $global:variable and $variable, etc...

The private scope can always (well with rare exceptions that aren't worth talking about) access a higher scope's variables. So inside your private foreach loop you can access the script variables, you don't have to set them over and over again.

Get-Variable -scope is a nifty way of playing around with how this works or again checking out that link.

adaz fucked around with this message at 19:54 on Feb 2, 2012

Wicaeed
Feb 8, 2005
Cool.

Another question:

In the email I am getting with the results, the formatting is crapping everything out on a single line, like so:
code:
20120106_ConfluenceC was removed from the DFS rotation 20120106_ConfluenceD was removed from the DFS rotation 20120127_ConfluenceD was transfered to DFS Folder 20120127_ConfluenceC was transfered to DFS Folder
I tried piping it to format-list but then I get a return like this:

code:
Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
How can I get it to put one entry on each line?

adaz
Mar 7, 2009

I forgot about that particular little annoyance. You need to change one line in the Send-Email command, set isBodyHTML to false

code:
$Email.IsBodyHtml = $false

Wicaeed
Feb 8, 2005
Mmmm, I don't think that's it. I have another script I use to send a separate email, however it uses two variables that only ever output a single line of text. I had to edit the body of the email to add some breaking

code:
Send-MailMessage -To $emailto -Subject "$Backup2k3Status - $sqlstatus" -Body $BackupFolder2k3cinfo`r`r`n$BackupFolder2k3Dinfo`r`r`n$sqlstatus -From $EmailFrom -SmtpServer $EmailServer

Siets
Sep 19, 2006

by FactsAreUseless
Just about there.

I now have my HTML completely stripped away to just the dates and values! (Thanks Adaz & Co.) What is left is a simple string that has a date followed by five or so values, then a new date and more values, etc. Ex:

code:
2012-29-01

450,000

340,000

220,000

20,300

56

(repeats with next date in same format as above)
How do you go through a string and grab values? In this case, I'm matching the date Jan 29 2012, but once I match it how do I tell Powershell to "go down 8 lines and get that number (20,300)"?

I think I'm just misunderstanding how people are using the square brackets after variables. $splitVal[10] for instance, what is this doing? Or would I use the System.String.Substring() method somehow?

(Sorry in advance for being so bad at string parsing. Haven't ever really had to do it in scripting before now!)

edit: :frogsiren: Script complete! Thanks again everyone!

Siets fucked around with this message at 02:40 on Feb 7, 2012

adaz
Mar 7, 2009

Wicaeed,

Well I know it works and is inserting a line terminator I just verified it. It's probably some quirk with whatever email client you're using that it is ignoring that character for some reason. If you check the $email.body before sending it the text should show up there with line breaks.


Siets,

$splitVal[10] is the 11th position in the array as array's are 0 based. So let's do this example. WE have the following values:

10,20,30,40,50,60

I want them into an array, so I'll call split(",") to put the individual elements into an array. The square brackets [number] are just how you access the different elements inside the array. Here is an example:

Only registered members can see post attachments!

adaz fucked around with this message at 19:08 on Feb 5, 2012

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe
I'm trying to improve the way we're doing some things with Powershell on a project I'm working on, particularly working with credentials. I've been doing some experimentation with the PSCredential object type, more or less using the method described here. Everything seems to work pretty well. The script I want to use this in gets executed from a variety of machines, but always as the same domain user. I copied the encrypted password file I created to a different server, but when I executed
code:
Get-Content secretfile.txt | ConvertTo-SecureString
I got an error reading "ConvertTo-SecureString : Key not valid for use in specified state." Can I not take an encrypted file from server to server like this, or am I just doing something wrong?

adaz
Mar 7, 2009

Correct, the key it generates is machine specific. If you need to run the script on multiple machines this is a decent enough workaround (to be honest, I've forgotten how I have worked around this in the past): http://powertoe.wordpress.com/2011/06/05/storing-passwords-to-disk-in-powershell-with-machine-based-encryption/

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

adaz posted:

Correct, the key it generates is machine specific. If you need to run the script on multiple machines this is a decent enough workaround (to be honest, I've forgotten how I have worked around this in the past): http://powertoe.wordpress.com/2011/06/05/storing-passwords-to-disk-in-powershell-with-machine-based-encryption/

Thanks for the link, that's an interesting approach. I only have a few different servers to work with, so having to create a separate password file is more annoying than anything else. I think I'll just do it that way, I was really just wanting done confirmation before I wasted any more time trying to figure out why it wasn't working.

adaz
Mar 7, 2009

To be honest the last time I ran into this I think I just used schtask command line tool to remotely schedule the script and save the credentials that way.

Dreadite
Dec 31, 2004

College Slice
Is this a place to ask for help with stitching code segments together?

I just need to do something small, but I'm new at this.

How would I connect a dumb foreach loop that just makes folders

code:
$folders = @("F:/test1", "F:/test2")
foreach ($folder in $folders)
{md $folder}
with a thing like this (that I found on the internet) that can set permissions on the aforementioned folders?

code:
$acl=Get-Acl $folder
$permission ="domain\user", "Full Control", "allow"
$accessrule = New-Object system.Security.AccessControl.FileSystemAccessRule $permission
$acl.setaccessrule($accessrule)
$acl | Set-Acl $folder
Sorry if this is trivial but I'm just trying to learn a little on the fly.

adaz
Mar 7, 2009

code:
$folders = @("F:\test1", "F:\test2")
foreach ($folder in $folders) {
md $folder

$acl=Get-Acl $folder
$permission ="domain\user", "Full Control", "allow"
$accessrule = New-Object system.Security.AccessControl.FileSystemAccessRule $permission
$acl.setaccessrule($accessrule)
$acl | Set-Acl $folder

}

Is this what you're looking for? To write it out, you loop through F:\Test1, and F:\test2. It creates the folders. Then adds Domain\User as full control (allow) on the acls of each folder. Replace Domain\User with appropriate, could also set a group (individual user permissions on folders noooooooooooooooo) by using a group name instead.

Siets
Sep 19, 2006

by FactsAreUseless
Just in case you are really new, what Adaz did was put your second chunk of code inside the code block of the first chunk of code you posted. A code block is just essentially "do all of the stuff inside of the { and } brackets." That code block is then run every time a new $folder is found inside of $folders- so if you have 10 folders, it will run the code block 10 times.

Dreadite
Dec 31, 2004

College Slice

Siets posted:

Just in case you are really new, what Adaz did was put your second chunk of code inside the code block of the first chunk of code you posted. A code block is just essentially "do all of the stuff inside of the { and } brackets." That code block is then run every time a new $folder is found inside of $folders- so if you have 10 folders, it will run the code block 10 times.

Yeah I understand this, and I appreciate it, because what I was doing wrong beforewas trying to breaking the md command and the get-acl segment into two blocks of curley braces, which obviously doesn't work.

This makes sense and is simpler than what I was trying to do. Thanks guys :)

Dreadite fucked around with this message at 16:03 on Feb 23, 2012

Dreadite
Dec 31, 2004

College Slice
Another thing I am having trouble doing is removing all of the access rules on the directories I create. I would like to be able to strip all the access rules and then specifically add the users permissions that I would like afterwards-


I tried this but it throws errors like
code:
 Cannot find an overload for "RemoveAccessRuleAll" and the argument count: "0"
From the MS article about that method, it should just remove all the access rules on that directory. Am I constructing this wrong?

code:
$acl=Get-Acl F:\test1
$permission1 ="$testuser1", "FullControl", "allow"
$permission2 ="$testuser2", "Modify", "allow"
$accessrule1 = New-Object system.Security.AccessControl.FileSystemAccessRule $permission1
$accessrule2 = New-Object system.Security.AccessControl.FileSystemAccessRule $permission2
$acl.removeaccessruleall()
$acl.setaccessrule($accessrule1)
$acl.setaccessrule($accessrule2)
$acl | Set-Acl F:\test1

adaz
Mar 7, 2009

RemoveAccessRuleAll just removes a single ACE, see this pretty good article for more details: http://technet.microsoft.com/en-us/library/ff730951.aspx

What I've usually found helpful when working with ACLs is to do something like this

code:
get-acl C:\modelDirectory | set-Acl F:\directory
This is the lazy way of doing it, basically create a directory that has the permissions you want to set on it then as you create your new directories pipe those ACLs to Set-ACL. Does that make sense?


There are also some scripting guys articles on Get-ACL(http://blogs.technet.com/b/heyscriptingguy/archive/2009/09/14/hey-scripting-guy-september-14-2009.aspx) and Set-ACL (http://blogs.technet.com/b/heyscriptingguy/archive/2009/09/16/hey-scripting-guy-september-16-2009.aspx), which actually explains what I'm doing above in more detail.

Jelmylicious
Dec 6, 2007
Buy Dr. Quack's miracle juice! Now with patented H-twenty!
Also, if you remove all access rights first, you won't have any rights yourself. Which means you don't have rights to set accessrights.

Dreadite
Dec 31, 2004

College Slice
Deeper into the rabbit hole!

Am I using the wrong class to set these permissions, since they show up only as "special" permissions? I'm using
code:
system.Security.AccessControl.FileSystemAccessRule
This is the result of using it to set my permissions:
http://imgur.com/a/VElWl

Korlac
Nov 16, 2006

A quintessential being known throughout the Realm as the 'Dungeon Master'. :rolldice:
For the Exchange Management Shell people out there on Exchange 2010, I worked up a custom function to parse all the Role Groups for individual commands per group membership. It's handy if you're trying to determine exactly what commands people get access to when they're a member of certain groups. You can specify a role group if you only want to see the commands that group gets. If you don't it will list all the commands available to all the groups, and of course you can sort/parse on the new properties.

code:
Function Get-RoleGroupCommands ([string]$Roleinput){
	If ($Roleinput -ne "" -and $Roleinput -ne $Null){
		$RoleName = get-rolegroup $Roleinput
		}
		Else {
		$RoleName = get-rolegroup
		}
		Foreach ($Rolegroup in $Rolename)
			{
			Foreach ($Role in $RoleGroup.roles)
				{
				$ManagementRole = Get-ManagementRole $Role
				$Actualrole = Get-ManagementRole $ManagementRole
				Foreach ($entry in $ActualRole.roleEntries)
					{
					New-Object PSObject -Property @{
						Name = $Rolegroup.name
						Linkedgroup = $Rolegroup.linkedgroup
						Role = $ActualRole.name
						Entry = $Entry.name
						Parameters = $Entry.parameters
						}
					}
				}
			}
		}

adaz
Mar 7, 2009

Dreadite posted:

Deeper into the rabbit hole!

Am I using the wrong class to set these permissions, since they show up only as "special" permissions? I'm using
code:
system.Security.AccessControl.FileSystemAccessRule
This is the result of using it to set my permissions:
http://imgur.com/a/VElWl

Whoops, missed this -- did you ever figure it out? At a casual glance it looks like everything is right but what type of right are you setting? deny? modify? allow? or something more esoteric?

Wicaeed
Feb 8, 2005
What's the easiest way to break out of a scriptblock in Powershell? I have a script that will generate quite a few errors if a variable is not set, which can happen if it is a certain date.

Can I add a simple If/Else statement to say something like:

code:
If ($variable -eq $null){
Goto next function
Else{
do something here
}
Edit: Hurr, a simple 'break' will work there. Another question regarding variables.

I've got two variables, one is a folder path, the other is a filename variable. I would like to combine the two to test the existence of the destination file. Code snippet follows:

code:
Foreach ($script:item in $DFSFilesToCopy){
    $script:ParentFoldername = $item | split-path -parent | split-path -leaf
    $script:ParentFolderStructure = $item | split-path -parent
    $script:DestinationFolder = "G:\$ParentFolderName"
    $script:SourceFolder = $ParentFolderStructure
        If ((Test-Path $item) -eq $True) {
        $script:DFSresult += "$item was copied to the DFS folder"
        $script:robocopy = robocopy.exe $SourceFolder $DestinationFolder $item.name /S /DCopy:T
        $robocopy
        }
        Else {
        $script:DFSresult += "$item was not copied because it already exists"
        }
}
When I do something like '$item.name' I get exactly what I want. How can I combine that with $DestinationFolder to get

code:
G:\ParentFolderName\Filename

Wicaeed fucked around with this message at 17:26 on Feb 29, 2012

Jelmylicious
Dec 6, 2007
Buy Dr. Quack's miracle juice! Now with patented H-twenty!
You can append strings with a simple + so:

$Destinationfolder + $item.name should work.

adaz
Mar 7, 2009

You can also use subexpression syntax
code:
$script:robocopy = "robocopy.exe $SourceFolder $($DestinationFolder)\$($item.name) /S /DCopy:T"
Do a get-help about_quoting_rules for the full version

Korlac
Nov 16, 2006

A quintessential being known throughout the Realm as the 'Dungeon Master'. :rolldice:
Does anyone know of any good Powershell scripts to parse IIS logs? Basically we get requests every once in a while to look for specific logon information in IIS based on a user's logon alias, but our IIS logs span several severs and I was wondering if there's a way to parse those logs from on location through a Powershell command?

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

Wicaeed posted:

What's the easiest way to break out of a scriptblock in Powershell? I have a script that will generate quite a few errors if a variable is not set, which can happen if it is a certain date.

Can I add a simple If/Else statement to say something like:

code:
If ($variable -eq $null){
Goto next function
Else{
do something here
}
Edit: Hurr, a simple 'break' will work there. Another question regarding variables.

It's purely a matter of style, but I find it cleaner to do something like
code:
If ($variable -ne $null){
{
do something here
}
Something about an empty if block just bugs me.

Phone
Jul 30, 2005

親子丼をほしい。
Is there a way to delete a row out of a CSV and then be able to export it out?

I know that $null will kill the row if you do something like $var[$i]=$null, but then Export-Csv throws an error about null values in a row when trying to export it out.

adaz
Mar 7, 2009

Phone posted:

Is there a way to delete a row out of a CSV and then be able to export it out?

I know that $null will kill the row if you do something like $var[$i]=$null, but then Export-Csv throws an error about null values in a row when trying to export it out.

yes! There probably is a non-ghetto way but this is what i've done.

code:
$csvImport = import-csv C:\blah.csv

$csvExport = $csvImport | where-Object {$_.PropToRemove -ne $Stuff}

$csvExport | export-Csv C:\blahfixed.csv 
Basically you run each row through where-Object, filtering out the rows you don't want. Then pipe the new object to Export-Csv

Korlac
Nov 16, 2006

A quintessential being known throughout the Realm as the 'Dungeon Master'. :rolldice:
So earlier I was asking for a script to parse IIS logs, and while I found a few on the internet, most were overly complex and didn't really meet my needs, so I made it myself.

code:
Function Get-CASIISLogs
	{
	$SRnumber = read-host -prompt "What is the SRX number for your incident?"
	$Dateinput = read-host -prompt "Input date to search. Use YYMMDD format, use as 120302 to search for logs for March 02, 2012. If you do not specify a value, today's date will be used by default."
		IF ($Dateinput -ne "" -and $Dateinput -ne $Null)
			{
			$Date = $Dateinput
			}
		Else
			{
			$Date = Get-Date -format yyMMdd
			}
	$User = read-host -prompt "Input user's account using domain\alias format."
	$Servers = Get-ClientAccessServer
	foreach ($server in $servers)
		{
		$Files = "\\" + $server + "\c$\iis\logfiles\W3SVC1\u_ex" + $Date + "*"
		$Content = Select-String -path $Files -pattern $User -SimpleMatch
		$Output = $Content | Out-File ~\desktop\$SRnumber.txt -append -width 2000
		$Output
		}
	}
The prompt for your ticket number is just a support thing, really that just determines the file name. So change that accordingly. Also, you may need to modify the $Files section to match where your IIS logs are stored by default in your Exchange Organization. This command will go out to all of your CAS boxes so there's no need to run it on multiple servers.

Korlac
Nov 16, 2006

A quintessential being known throughout the Realm as the 'Dungeon Master'. :rolldice:
I made another log parsing script since I got my IIS one working so well. This one is designed to parse SMTP protocol logs on your Hub transport server. There's a bit more logic involved here, and you need to know if the SMTP event is a Receive or a Send event, as that affects where the script will search. Once again, you may need to modify the $Files parameter if you don't store your logs in the same location.

code:
Function Get-ProtocolLogs
	{
	$SRnumber = read-host -prompt "What is the SRX number for your incident?"
	$TransportEvent = read-host -prompt "Is this a SEND or RECEIVE event? Either type SEND or RECEIVE."
		If ($TransportEvent -eq "RECEIVE")
		{
		$Recipient = read-host -prompt "What is the address of your recipient?"
		}
		If ($TransportEvent -eq "SEND")
		{
		$Sender = read-host -prompt "What is the address of your sender?"
		}
	$Dateinput = read-host -prompt "Input date to search. Use YYYYMMDD format, use as 20120302 to search for logs for March 02, 2012. If you do not specify a value, today's date will be used by default."
		IF ($Dateinput -ne "" -and $Dateinput -ne $Null)
			{
			$Date = $Dateinput
			}
		Else
			{
			$Date = Get-Date -format yyyyMMdd
			}
	$Servers = Get-TransportServer
		IF ($TransportEvent -eq "SEND")
		{
		foreach ($server in $servers)
			{
			$Files = "\\" + $server + "\c$\exchsrvr\TransportRoles\Logs\ProtocolLog\SmtpSend\SEND" + $Date + "*"
			$Content = Select-String -path $Files -pattern $Sender -SimpleMatch -Context 10, 10
			$Output = $Content | Out-File ~\desktop\$SRnumber.txt -append -width 1000
			$Output
			}
		}
		IF ($TransportEvent -eq "RECEIVE")
		{
		foreach ($server in $servers)
			{
			$Files = "\\" + $server + "\c$\exchsrvr\TransportRoles\Logs\ProtocolLog\SmtpReceive\RECV" + $Date + "*"
			$Content = Select-String -path $Files -pattern $Recipient -SimpleMatch -Context 10, 10
			$Output = $Content | Out-File ~\desktop\$SRnumber.txt -append -width 1000
			$Output
			}
		}
	}
Because protocol logs are not stored in perfect event order, this script will grab 10 lines before and after the pattern match in an attempt to get you the full SMTP communication, which should grab most of the data you're looking for.

Wicaeed
Feb 8, 2005
So recently I've noticed some strange behavior in Powershell ISE and scheduled tasks.

I can load up/edit a script in ISE, and when it comes time to run it, I hit F5. This loads the script but nothing really happens. I have to manually type the function that is calling each scriptblock in to the powershell CLI to get it to run properly.

This is affecting scheduled tasks as well. I did install Powershell 3.0 beta on my workstation and have been using it to remote powershell tab to my servers, but I still have 2.0 installed on my servers, however it happens on the servers as well if I am using Powershell ISE in an RDP session.

Any ideas, as I'm completely befuddled by this behavior.

RICHUNCLEPENNYBAGS
Dec 21, 2010
So does Powershell just lack shortcuts to jump around text, or do I just not know them, or what? Like in bash you have a ton of shortcuts like ^a for the beginning of the line, alt-f to go forward one word, ^w to delete a word, etc, but apparently you just have to hold down the arrow button forever to do this kind of stuff with Powershell which is annoying.

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

RICHUNCLEPENNYBAGS posted:

So does Powershell just lack shortcuts to jump around text, or do I just not know them, or what? Like in bash you have a ton of shortcuts like ^a for the beginning of the line, alt-f to go forward one word, ^w to delete a word, etc, but apparently you just have to hold down the arrow button forever to do this kind of stuff with Powershell which is annoying.

Try home and end. Ctrl -> and ctrl <- will go one word at a time. That's not just powershell though, that's standard Windows behavior.

RICHUNCLEPENNYBAGS
Dec 21, 2010

stubblyhead posted:

Try home and end. Ctrl -> and ctrl <- will go one word at a time. That's not just powershell though, that's standard Windows behavior.

I guess Unix has warped my thought process because I knew those were standard Windows behaviors and did not think to try them in Powershell. :downs: Point taken.

adaz
Mar 7, 2009

Wicaeed posted:

So recently I've noticed some strange behavior in Powershell ISE and scheduled tasks.

I can load up/edit a script in ISE, and when it comes time to run it, I hit F5. This loads the script but nothing really happens. I have to manually type the function that is calling each scriptblock in to the powershell CLI to get it to run properly.

This is affecting scheduled tasks as well. I did install Powershell 3.0 beta on my workstation and have been using it to remote powershell tab to my servers, but I still have 2.0 installed on my servers, however it happens on the servers as well if I am using Powershell ISE in an RDP session.

Any ideas, as I'm completely befuddled by this behavior.

My guess is a DLL that got hosed up, I mean does it happen on other workstations that didn't have 3.0 beta installed?

And Korlac thanks for those IIS log parsers, I started to write something then got bogged down at work.

adaz fucked around with this message at 05:35 on Mar 6, 2012

Phone
Jul 30, 2005

親子丼をほしい。
So I've been tasked with automating some auditing because the previous method was some lengthy and involved process that included Access databases. I'm pretty much done with all of this due to Powershell.

God drat I loving love the Import-Csv cmdlet.

I'm horrible at programming, but I am apparently a programming god to my coworkers because I know about for loops and know about objects/arrays.

GPF
Jul 20, 2000

Kidney Buddies
Oven Wrangler
Probably my favorite part of Powershell 2.0 is the remoting using PSSession.

I built a utility at work for dealing with print servers. It creates multiple records, not only in the print servers, but also in DHCP and NPS. Without remoting, it would take much longer to pull the data to the local machine and then send the replies back up.

And, Phone, Import-CSV and Get-Content were brought to us by $deity itself.

Wicaeed
Feb 8, 2005
Seriously, I've quite thoroughly enjoyed my time with Powershell thus far, I just wish I had more excuses to use it at work :(

Adbot
ADBOT LOVES YOU

Jelmylicious
Dec 6, 2007
Buy Dr. Quack's miracle juice! Now with patented H-twenty!

Wicaeed posted:

Seriously, I've quite thoroughly enjoyed my time with Powershell thus far, I just wish I had more excuses to use it at work :(

Is there anything you do semi-regularly that could be automated? Go on! Script yourself out of a job!

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