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
adaz
Mar 7, 2009

Serfer posted:

Ok, I've got a problem. I have a datatable (returned data from an SQL query), and I need to count up the items that have the same of a single element.
So there are the following fields:

HostName DisplayName EntryDate Usages

and I need to count up all the items that have the same displayname. I understand essentially how it would be done (probably easiest would be a dynamic variable with the same name, that just gets incremented), but I'm unfamiliar with how these are actually done in Powershell.

Hrrm. I don't know if this is the right way to do it, but something like this would work, or more precisely it is the first thing that came to mind ($dt is your dataTable)
code:
$arrDispNames = new-object collections.arraylist
$z = 0

for($I=0;$I -lt $Dt.rows.count;$I++) {
   if($arr.DispName.Contains($dt.rows[$i].displayname)) {
        $z = $z + 1
   }else {
      [void]arrDispNames.add($dt.rows[$i].displayname)
   }
}
write-host $z
You could also do it using Where-Object and Select-Object -unique but this would take roughly forever in my experience if the dataset is large at all.

If you want to create a new dynamic variable you can use the New-Variable cmdlet inside a for loop, but I guess not sure exactly what you were asking. Did you want to find out how many times each unique instance of displayName was duplicated? Like in this theoretical table:

pre:
HostName   DisplayName      EntryDate            Usages
compy1      blahblah         1/1/1000             10000
compy2      blahblah         1/1/1000             10000
compy3      foobar           1/1/1000             10000
compy4      snafu            1/1/1000             10000
compy5      foobar           1/1/1000             10000
compy6      foobar           1/1/1000             10000
Would you want to know blahblah was used twice, foobar three times, and snafu once?

adaz fucked around with this message at 00:15 on May 3, 2011

Adbot
ADBOT LOVES YOU

Serfer
Mar 10, 2003

The piss tape is real



adaz posted:

Would you want to know blahblah was used twice, foobar three times, and snafu once?
Pretty much, yes

adaz
Mar 7, 2009

Serfer posted:

Pretty much, yes

That makes more sense.

Again, assuming $dt is your data table... there might be a simpler way of doing this but since you probably want a nicely formatted file or table to look at after it's finished I threw in the export-Csv

code:
# for CSV export.
$exportTable = @()

# Build an array of our distinct host names.
[array]$arrDistinct = $dt.rows | select-Object HostName -unique

# Loop through each unique address & find number of occurrences.
foreach($hostName in $arrDistinct) {
     $OutObj = "" | select Hostname,Occurrences
     $count = $dt.rows | Where-Object {$_.hostName -match $hostName} | measure-Object 
     $OutObj.hostname = $hostAddr.hostname
     $OutObj.occurrences = $count.count
     $exporttable += $outObj
}

#export our CSV file out
$exportTable | export-Csv C:\temp\hostOcc.csv -noTypeInformation
If you really wanted to get fancy and make something that could be reused...

code:
<#
       .SYNOPSIS

          Passed a DataTable object, counts the number of specified property occurrences and exports out a csv file

      .EXAMPLE

            .\Count-DataTableProperties -Datatable $dt -property hostName -exportPath C:\temp\blah.csv

            Passed $dt it checks for the number of occurrences of the property hostName and exports to c:\temp\blah.csv

      .NOTES

            NAME: Count-DataTableProperties.ps1
            AUTHOR: Adaz
            DATE: 05/04/2011

#Requires -Version 2.0
#>
param(
[parameter(position=0,mandatory = $true)]
$dataTable,
[parameter(position=1,mandatory = $true)]
[string]
$property,
[parameter(position=2,mandatory = $true)]
[string]
$exportPath
)

$exportTable = @()

[array]$arrDistinct = $dataTable.rows | select-Object $property -unique

foreach($Obj in $arrDistinct) {
     $OutObj = "" | select $property,Occurrences
     $count = $dataTable.rows | Where-Object {$_.$($property) -match $obj} | measure-Object 
     $OutObj.$($property) = $obj.$($property)
     $OutObj.occurrences = $count.count
     $exporttable += $outObj
}
$exportTable | export-Csv $exportPath -noTypeInformation
e: woops had some errors in the param statement

adaz fucked around with this message at 00:07 on May 5, 2011

CuddleChunks
Sep 18, 2004

I want to rewrite my powershell handbrake script in C# so I can slap a big dumb gui on it but look at that code up above. Just look at it.

:3: Oh powershell, you're so pretty.

ghostinmyshell
Sep 17, 2004



I am very particular about biscuits, I'll have you know.
I went to a Powershell event today and the speaker explained how you could mount Active Directory and then rm -f the entire thing like a real *nix admin. That is the moment I decided to learn Powershell.

Anyone have book recommendations? Need a newbie book and then something that has some meat on it. I already ordered http://www.manning.com/jones/

wwb
Aug 17, 2004

No real expert, but the other manning powershell books are first-rate too.

adaz
Mar 7, 2009

ghostinmyshell posted:

I went to a Powershell event today and the speaker explained how you could mount Active Directory and then rm -f the entire thing like a real *nix admin. That is the moment I decided to learn Powershell.

Anyone have book recommendations? Need a newbie book and then something that has some meat on it. I already ordered http://www.manning.com/jones/

hahahahaahha I never thought about it but you definitely could.

The O'Reilly Powershell Cookbook is a nice handy reference (http://oreilly.com/catalog/9780596528492) but it's a bit out of date and doesn't have anything on version 2. Other than that, the Windows Powershell in Action is also a good in depth guide, but again is only v1.

I haven't read any of the newer books on V2 unfortunately, but the differences are mainly minimal - it is better because it comes with remoting, transactions, try/catch and some new cmd-lets so a V1 book is a good starter and learning the new stuff isn't that hard.

adaz fucked around with this message at 17:01 on May 5, 2011

Z-Bo
Jul 2, 2005
more like z-butt
I am in disbelief.

I was writing a PowerShell script to dump our database schema to version control and ran into the stupidest bug in the whole world: [PS V2 RTM] Multiple Ambiguous Overloads

Wow! This totally wasted my entire afternoon trying to figure out. Also, unfortunately, the workaround in the article doesn't appear to work for me. ALL I WANT TO DO IS DUMP USER DEFINED FUNCTIONS and AGGREGATES!!! This problem doesn't occur for Tables, Views, Triggers and Stored Procedures due to the interface differences between those and UDFs and UDAs.

I tried the workaround suggested in the above link, but it was ultimately an epic failure.

Right now I am trying to figure out how to use System.Reflection to invoke the right signature in PowerShell, which is gross.

Help me.

code:
param 
(
  [string] $server,
  [string] $database,
  [string] $schema = "dbo",
  [string] $output_directory = "$HOME\Desktop\repos\dump\"
)

# Example call
# C:\SQL\Powershell\Examples\script_data.ps1 ".\sql2005" "tempdb" "dbo" "temp"
# or specify output file
# C:\SQL\Powershell\Examples\script_data.ps1 ".\sql2008" "tempdb" "dbo" "temp" "c:\temp\temp.sql"

if ($server -eq $null)
{
	exit;
}
if ($database -eq $null)
{
	exit;
}

Remove-Item -Force -Recurse -LiteralPath "$output_directory\UserDefinedFunction\"

New-Item -Force -Type Directory -Path "$output_directory\UserDefinedFunction\"

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Management.Sdk.Sfc") | out-null

$srv = New-Object ("Microsoft.SqlServer.Management.SMO.Server") $server
$db = New-Object ("Microsoft.SqlServer.Management.SMO.Database")
$tbl = New-Object ("Microsoft.SqlServer.Management.SMO.Table")
$scripter = New-Object ("Microsoft.SqlServer.Management.SMO.Scripter") ($server)

# Get the database and table objects
$db = $srv.Databases[$database]
$tables = $db.tables | Where-object { $_.schema -eq $schema } 

# Set scripter options to ensure only schema is scripted
$scripter.Options.ScriptSchema = $true;
$scripter.Options.ScriptData = $false;
$scripter.Options.NoCommandTerminator = $false; # Include GOs after every script
$Scripter.Options.DriAll=$True; # DRI = "Declarative Referential Integrity"
$Scripter.Options.IncludeHeaders=$False
$Scripter.Options.ToFileOnly=$True
$Scripter.Options.WithDependencies=$False

$udfs = $db.UserDefinedFunctions | Where-object { $_.Schema -eq $schema } 

if ($udfs.Count -ne 0)
{
	foreach ($udf in $udfs)
	{
		[Microsoft.SqlServer.Management.Smo.UrnCollection] $smoObjects = New-Object Microsoft.SqlServer.Management.Smo.UrnCollection;
		$smoObjects.Add($udf.Urn);
		Write-Host "Dumping $udf";
		$output_filename = $output_directory + "\UserDefinedFunction\" + $udf.Name + ".sql";
		$scripter.Options.FileName = $output_filename;
		$Scripter.Options.AppendToFile=$False;
		$Scripter.Options.ScriptDrops=$True;
		$Scripter.Options.IncludeIfNotExists=$True;
		$Scripter.Script([Microsoft.SqlServer.Management.Smo.UrnCollection]$($smoObjects));
		$Scripter.Options.ScriptDrops=$False;
		$Scripter.Options.IncludeIfNotExists=$False;
		$Scripter.Options.AppendToFile=$True
		$Scripter.Options.Permissions = $True;
		$Scripter.Script([Microsoft.SqlServer.Management.Smo.UrnCollection]$($smoObjects));
	}
}
:psyduck:

Z-Bo fucked around with this message at 21:27 on May 6, 2011

adaz
Mar 7, 2009

Which line is it actually having issues with the multiple ambiguous overloads?

At home, don't have access to work stuff to play with a sql table and test.

Z-Bo
Jul 2, 2005
more like z-butt
code:
$Scripter.Script([Microsoft.SqlServer.Management.Smo.UrnCollection]$($smoObjects));
Originally, my code was just:

code:
$Scripter.Script($udf);
But that didn't work either.

Both say roughly the following error:

code:
Multiple ambiguous overloads found for "Script" and the argument count: "1".
At C:\Users\ME\Desktop\dumper\Script-DatabaseObjectsNew.ps1:188 char:19
+         $Scripter.Script <<<< ([Microsoft.SqlServer.Management.Smo.UrnCollection]($($smoObjects)));
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest
I am trying to get MethodInfo Invoke working but it is a huge PITA in PowerShell as compared to doing it in C#.

I've also tried:

code:
$params = new-object object[] 1;
$params[0] = $smoObjects;
[Microsoft.SqlServer.Management.SMO.Scripter].GetMethod("Script", [System.Type[]] @([Microsoft.SqlServer.Management.Smo.UrnCollection])) | % { $_.Invoke($scripter, $params) }
but it produces the following error:

code:
Exception calling "Invoke" with "2" argument(s): "Script failed for Server 'MyServerName'. "
At C:\Users\ME\Desktop\dumper\Script-DatabaseObjectsNew.ps1:189 char:155
+         [Microsoft.SqlServer.Management.SMO.Scripter].GetMethod("Script", [System.Type[]] @([Microsoft.SqlServer.Mana
gement.Smo.UrnCollection])) | % { $_.Invoke <<<< ($scripter, $params) }
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodTargetInvocation

Z-Bo fucked around with this message at 22:15 on May 6, 2011

adaz
Mar 7, 2009

I can't get it to reproduce the error (also those ; aren't needed :))

So I ran a parsed down version of your script and it worked fine with no errors whatsoever. This makes me think that maybe you're passing an empty $smoObjects or something stupid to it -- if you try to manually do all this by hand and check each output object what type is smoObjects.GetType() returning to you and are there actually objects being stored in it?

Swink
Apr 18, 2006
Left Side <--- Many Whelps
So we're almost finished migrating to 2008R2 and Exchange 2010, and I heard on the wire that you can manipulate mailbox permissions using PS. For example, a user would call me and say that they need to give editor writes on their inbox to their new assistant.

Could I do up a script in PS that would do this for me? If so, is there anything I can't do with powershell & exchange?

adaz
Mar 7, 2009

Swink posted:

So we're almost finished migrating to 2008R2 and Exchange 2010, and I heard on the wire that you can manipulate mailbox permissions using PS. For example, a user would call me and say that they need to give editor writes on their inbox to their new assistant.

Could I do up a script in PS that would do this for me? If so, is there anything I can't do with powershell & exchange?

You heard correctly! The cmdlets you want are:

Add-MailboxFolderPermission http://technet.microsoft.com/en-us/library/dd298062.aspx

Remove-MailboxFolderPermission http://technet.microsoft.com/en-us/library/dd351181.aspx

IF you want to apply permissions to the entire mailbox - say if you're creating a shared mail user and want to give a group of individual users full access control of it - you want Add-MailboxPermission http://technet.microsoft.com/en-us/library/bb124097.aspx

The full list can be found here: http://technet.microsoft.com/en-us/library/bb124413.aspx

As far as what you can't do, I don't honestly know, everything can be done as far as I know. But I'm not an exchange admin, and only really handle user facing stuff like mailboxes, calendars, and resources. In general though the exchange management console is just a pretty front-end for powershell and as far as I know drat near everything can be done through just scripts and powershell.

adaz fucked around with this message at 04:30 on May 7, 2011

Swink
Apr 18, 2006
Left Side <--- Many Whelps
I'm no exchange admin myself, but Mailbox/Folder permissions are a daily thing. So this all looks very promising. Thanks!

Z-Bo
Jul 2, 2005
more like z-butt

adaz posted:

I can't get it to reproduce the error (also those ; aren't needed :))

So I ran a parsed down version of your script and it worked fine with no errors whatsoever. This makes me think that maybe you're passing an empty $smoObjects or something stupid to it -- if you try to manually do all this by hand and check each output object what type is smoObjects.GetType() returning to you and are there actually objects being stored in it?

Thanks for the help thinking through how to better debug this problem.

1) smoObjects.GetType() --> an SMO UrnCollection
2) smoObjects.Count --> 1

Can anyone help me with the reflective invoking of the Scripter.Script(...) method?

I also don't understand why System.Reflection.MethodInfo's Invoke(..., ...) method isn't recognized by PowerShell.

It may also help to repeat that this appears to be a known PSv2 bug and I need a workaround.

Z-Bo fucked around with this message at 15:13 on May 7, 2011

adaz
Mar 7, 2009

Ok, I was able to get this working with the small changes to your code connecting to the same version of sql server , powershell v2, and windows 7. Now, the one thing that might be different is the $udfs I'm passing contains 58 objects, not just 1 however the Type is still the same even if you just do 1 so it really shouldn't matter.

I was also getting the multiple ambiguous overloads until I removed the type conversions you had forced in Script and changed the SmoObjects to remove the unnecessary forced cast after you declare it.

code:
	foreach ($udf in $udfs)
	{
               $smoObjects = New-Object Microsoft.SqlServer.Management.Smo.UrnCollection
		$smoObjects.Add($udf.Urn)
		Write-Host "Dumping $udf"
		$output_filename = $output_directory + "\UserDefinedFunction\" + $udf.Name + ".sql"
		$scripter.Options.FileName = $output_filename;
		$Scripter.Options.AppendToFile=$False
		$Scripter.Options.ScriptDrops=$True
		$Scripter.Options.IncludeIfNotExists=$True
		$Scripter.Script($smoObjects)
		$Scripter.Options.ScriptDrops=$False
		$Scripter.Options.IncludeIfNotExists=$False
		$Scripter.Options.AppendToFile=$True
		$Scripter.Options.Permissions = $True
		$Scripter.Script($smoObjects)
	}
Now if you're asking me why it failed I'm not entirely sure. For one, when I first tested this copy/paste was messing with me and my RDP session into work so I was hand typing a lot of this and omitting the explicit casts, hence why it worked. Why the casts caused it to fail on the other hand is something I'm not sure on.

adaz fucked around with this message at 22:12 on May 8, 2011

Z-Bo
Jul 2, 2005
more like z-butt
This time it is complaining it can't find the Script method on the Scripter object.

code:
Exception calling "Script" with "1" argument(s): "Script failed for Server 'asp6'. "
At C:\Users\ME\Desktop\repos\dumper\Script-DatabaseObjectsNew.ps1:184 char:18
+     $Scripter.Script <<<< ($smoObjects)
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException
This is completely insane. The code works on the foreach block above it that goes through all the stored procedures, and so on through tables, views, triggers.

I am going to code this up in C# just to make sure I don't suddenly completely suck as a programmer.

adaz
Mar 7, 2009

Z-Bo posted:

This time it is complaining it can't find the Script method on the Scripter object.

code:
Exception calling "Script" with "1" argument(s): "Script failed for Server 'asp6'. "
At C:\Users\ME\Desktop\repos\dumper\Script-DatabaseObjectsNew.ps1:184 char:18
+     $Scripter.Script <<<< ($smoObjects)
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException
This is completely insane. The code works on the foreach block above it that goes through all the stored procedures, and so on through tables, views, triggers.

I am going to code this up in C# just to make sure I don't suddenly completely suck as a programmer.

I should mention i was getting a similar error and it turned out to be because the output directory didn't exist, the exception is actually an error executing the script, not that it can't find the method

Z-Bo
Jul 2, 2005
more like z-butt
Yup! Actually, debugging a little further thanks to C# made it a little clearer what the issue was. Basically, $udfs was null - I started testing on a new database today and hadn't compiled UDFs or UDAs yet.

So this was a totally different problem from the other day. Your code works, it just needs:

code:
if ($udfs)
{
  #foreach loop here
}
What a pain in the rear end.

Edit: Thanks for your help.

adaz
Mar 7, 2009

Glad to hear it's finally working.

It does all bring up a good point about powershell, the lack of a real built in debugger is a pretty huge pain in the rear end a lot of times, especially if (like this was) your script is calling a bunch of .NET classes. It becomes 1/3rd guesswork, 1/3rd stepping through things yourself to find out what's going on, and 1/3rd experience when the errors get thrown. It also doesn't help that powershell hides a lot of the complexity behind the scenes making debugging certain things a nightmare (hence that multiple ambiguous overloads wasn't really the problem, but the weird type being passed to it).

On the other hand, playing with properties and methods of .NET classes is actually easier to do in powershell than in like visual studio if you just want to real quick know if it works, or just making some proof of concept code.

I do appreciate that script though, on my List Of Things To Do had been a script to pull off all the stored procedures/functions off a DB and hey now I have one

adaz fucked around with this message at 21:42 on May 9, 2011

Z-Bo
Jul 2, 2005
more like z-butt
Thanks.

For debugging, on the SQLPSX project I told everyone my general trick fellow goon Victor and I came up with for helping improve PowerShell tracing. PowerShell Tracing module just is too verbose and non-configurable as far as I can tell (compared to say C# or VB.NET or any .NET language). So what we did 2 years ago was this simple idiom:

code:
# Wrap ActualCommand in Invoke-Command, for logging purposes
function Invoke-Command ($argument_1, $argument_2)
{
	if (!$argument_1)
	{
		throw "`$argument_1 is not defined"
	}
	if (!$argument_2)
	{
		throw "`$argument_2 is not defined"
	}

	$invocation = {ActualCommand -Argument1 $argument_1 -Argument2 $argument_2}
	Write-Host "$invocation`r"
	Write-Host "`$argument_1=$argument_1, `$argument_2=$argument_2"
	& $invocation

	if ($LASTEXITCODE -ne 0)
	{
		$LASTEXITCODE
		throw "$invocation`r`$argument_1=$argument_1, `$argument_2=$argument_2`r exited with an error return code: $LASTEXITCODE"
	}
}
This tells you most things you want to know about the program you called:
  • What program did I actually call when I ran this PS function?
  • What arguments were passed to it?
  • Did I make any mistakes when calling this PS function?
  • Did the program complete without errors? If there are errors, use exception handling instead of having to check return codes. Useful for very large scripts Victor and I were writing.

If you scroll back in this thread, I promised to post stuff like this a long, long time ago but was just too lazy.

The basic idea is it lets you abstract away the underlying Windows command line program you are wrapping, and provide PowerShell defensive error handling for it. You can also use it to check that the program even exists, and possibly even install it if it doesn't.

I need to improve it so that it is generic. The signature should be:

code:
function Invoke-Command ($command, $args)
And rather than use the syntactic sugar { -Argument_1 = $argument_1 } for script blocks, just build the script block imperatively using the underlying PowerShell API.

quote:

I do appreciate that script though, on my List Of Things To Do had been a script to pull off all the stored procedures/functions off a DB and hey now I have one

I can post the final version here if people like, but I might put together a polished version for the ISE module in SQLPSX (I am a core contributor to that project, although none of my modules have yet to make it into a release/been reviewed by the team; I am working on a super-awesome profiling and tracing SQLPSX API that hooks into the SqlIse module since the long-term goal of the project is to let you use PowerShell-ISE to replace the god awful SQL Server Management Studio).

Z-Bo fucked around with this message at 00:43 on May 10, 2011

Z-Bo
Jul 2, 2005
more like z-butt
Just chiming in to say: Cha-CHING!

Googled "Powershell ScriptBlock class" today to go lookup the documentation on how to rewrite my Invoke-Command wrapper, and found somebody else's ConvertTo-ScriptBlock snippet.

This is so incredibly useful I felt I had to share it with you all and rejoice.

TastyShrimpPlatter
Dec 18, 2006

It's me, I'm the
When using trap, does the trap block need to be placed before the lines that could throw an exception, or can it be placed anywhere while it's still in the same block?

adaz
Mar 7, 2009

MrSamurai posted:

When using trap, does the trap block need to be placed before the lines that could throw an exception, or can it be placed anywhere while it's still in the same block?

It can be placed before, it will attempt the trap statement in the block first, doesn't matter if it comes before or after the code. This is a pretty good overview of traping in powershell http://huddledmasses.org/trap-exception-in-powershell/. Honestly ever since v2 I've switched everything to try/catch blocks

TastyShrimpPlatter
Dec 18, 2006

It's me, I'm the

adaz posted:

It can be placed before, it will attempt the trap statement in the block first, doesn't matter if it comes before or after the code. This is a pretty good overview of traping in powershell http://huddledmasses.org/trap-exception-in-powershell/. Honestly ever since v2 I've switched everything to try/catch blocks

Thanks for the info. I found that page before, but I didn't remember if it explicitly said anything about where trap blocks need to be placed.

adaz
Mar 7, 2009

MrSamurai posted:

Thanks for the info. I found that page before, but I didn't remember if it explicitly said anything about where trap blocks need to be placed.

I actually don't' remember if it does or not, but if you repeat their experiments (or just look at the code examples) you can see they are mainly placing trap blocks before the code. I tested it with a few of mine that I haven't converted to try/catch blocks (I usually place mine at the end, just swapped to front) and it worked the same.

Rabid Snake
Aug 6, 2004



Is there an easy way to send an email to a email alias when a script throws an error? We're using Office 365 to handle our exchange server so the SMTPclient class won't work for us. We've tried to use outlook but it throws security errors. Anyone have experience with using outlook to send an email with a log attachment file when the script throws an error?

Cronus
Mar 9, 2003

Hello beautiful.
This...is gonna get gross.

Rabid Snake posted:

Is there an easy way to send an email to a email alias when a script throws an error? We're using Office 365 to handle our exchange server so the SMTPclient class won't work for us. We've tried to use outlook but it throws security errors. Anyone have experience with using outlook to send an email with a log attachment file when the script throws an error?

You should be able to use Send-MailMessage if you're using PS 2.0, and pass the $error variable to the body.

http://technet.microsoft.com/en-us/library/dd347693.aspx

I abuse the hell out of it for custom reporting, it's pretty flexible just make sure you process all your objects to formatted strings before attempting to send or it will just look like garbage.

Serfer
Mar 10, 2003

The piss tape is real



How can I get my data back after using format list?

I'm using "get-eventlog -computername srv01 -logname system -source print -after $date"
and then piping through fl to get just a couple properties, but if I use convertto-csv after that, I just get a bunch of UUID's instead of the textual data. Obviously I'm just being stupid and there's something obvious that I'm overlooking.

Cronus
Mar 9, 2003

Hello beautiful.
This...is gonna get gross.
Pipe it to Select-Object for conversion to a CSV format:
code:
$var | select-object name, time, info | export-csv stuff.csv
When you do Get-EventLog it's returning an object, so to convert you have to pull data out of the object you want and Export to CSV/XML from there.

Format-List is really for display purposes or pure string output. So alternatively you can do this:

code:
$var | fl name, time, info | out-file stuff.txt
and you'll see the data you want, but in pure text. It just depends on what you want or what you plan to do with the results. I usually output to CSV so that I can collate them from multiple sources using Import-CSV.

adaz
Mar 7, 2009

Export-CSV is one of the worst behaved cmd-lets, or one of the worst documented one I'm not sure which but it basically never ever behaves how you would expect it to. What cronus said will work, the other trick is to make your own custom objects, add them to a array, and export that out. Also works well if you're trying to combine information from multiple cmd-lets and so forth to add to a single csv file

Something like this

code:
$exportTable = @()
$stuff = get-eventlog -computername srv01 -logname system -source print -after $date

foreach($event in $stuff) {
  $OutObj = "" | select print,date,blah
  $outobj.print = $event.print
  $outObj.date = $event.date.ToString()
  $exportTable += $outObj
}

$exportTable | export-Csv C:\temp\blah.csv -NoTypeInformation

Phone
Jul 30, 2005

親子丼をほしい。
Background: To kill some time at work and "increase my worth" (read: kill time) I've read up on some Powershell tutorials. I'm new to IT so tricks aren't popping out of my rear end all of the time and I'm really loving horrid at programming, but today was a day where I knew I could have streamlined a lot of stuff just if I knew a bit more; I know how batch files work and I know that PS can do all sorts of fun things. I decided to make a batch file to silently install a dozen Windows Updates, it took me a few tries but I figured out the syntax. I did it the long way and just copied the whole path and filename into notepad to do it. I know that there's a super easy way to get this done with less ctrl+c/v action.

The meat: I can get PS to just dump all of the files with the
code:
get-childitem -Filter *.msu -Name | out-file yourmom.txt
but I want to get it where I can put a string before and after so I can make a batch file without the ctrl+c/v action.

Basically I want to go from
code:
KB1.msu
KB2.msu
KB3.msu
To
code:
fancy.exe $directory-path/KB1.msu /flag1 /flag2
fancy.exe $directory-path/KB2.msu /flag1 /flag2
fancy.exe $directory-path/KB3.msu /flag1 /flag2
But I'm horrible at programming.

Cronus
Mar 9, 2003

Hello beautiful.
This...is gonna get gross.
You'll laugh it's so easy, but there are a few gotchas:

code:
$updates = Get-ChildItem -Filter *.msu -Name

// the loop
$updates | ForEach-Object{Invoke-Expression -command "'fancy.exe $_ /flag1 /flag2'"}
There are a number of ways to approach it, this is just one way.

The key part here is the $_, which represents the current index within the array of items in $updates (the list of files, basically) that it iterates through.

Also, by default PS will not run commandline strings as is, so that's why you use Invoke-Expression to execute the commands. Note the single quotes inside the double, without them it will treat spaces as multiple lines which you don't want.

And how to do the whole thing in one line using aliases and no need for file outputs:
code:
gci *.msu -name | %{iex -command "'fancy.exe $_ /flag1 /flag2'"}

Phone
Jul 30, 2005

親子丼をほしい。
That will execute the command though, not output it to a batch/text file, correct? I think that might be another gotcha. I'm looking to do it this backward rear end way because I'm updating thin clients with Windows 7 Embedded.

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

Moey
Oct 22, 2010

I LIKE TO MOVE IT
So I borrowed Spudman's script that scrapes computer name/model stuff by subnet. I am now trying to modify it to bring back much more than that. I am having a slight problem though getting memory to come back through the script.

To get back memory, I am using this.

(Get-WmiObject Win32_PhysicalMemory | measure-object Capacity -sum).sum/1mb

How do I throw that in my loop so I can assign it to a variable

I have tried a few different things, but here is the error I am getting

code:
You must provide a value expression on the right-hand side of the '-' operator.
At C:\Users\Moey\Desktop\CPUInfoNew.ps1:37 char:87
+   $mem = (Get-WmiObject Win32_PhysicalMemory | measure-object Capacity -sum).sum/1mb - <<<< Computer $ip -Credential $creds -ErrorAction SilentlyContinue
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpectedValueExpression
Another semi-related question, any suggestions on a good Powershell book? I like automation, so I figure might as well dive into this.

Mully Clown
Aug 1, 2004

I handle my piss like the great big frilly girls blouse that I am
That error is coming up because it thinks you are trying to do a subtraction.

code:
.sum/1mb - <<<< Computer
At face value you'd think you accidentally did a typo and really meant -computer. What has really happened is that you've mixed up which parameters belong with which Cmdlets. You need to put all the parameters with Get-WmiObject before you can pipe it to Measure-Object.

code:
$mem = (Get-WmiObject -Class Win32_PhysicalMemory -ComputerName $ip -Credential $creds -ErrorAction SilentlyContinue | Measure-Object Capacity -Sum).sum/1MB

Moey
Oct 22, 2010

I LIKE TO MOVE IT
The <<<< Computer part was added in once it errored out.

For the code, I need the | measure-object Capacity -sum as if I just do Get-WmiObject Win32_PhysicalMemory, it brings back a table of stuff that I am not interested in.


I feel like this is getting close, I am just missing something stupid.

$mem = (Get-WmiObject Win32_PhysicalMemory | measure-object Capacity -sum).sum/1mb -Computer $ip -Credential $creds -ErrorAction SilentlyContinue | ForEach-Object {$_.Capacity}

Mully Clown
Aug 1, 2004

I handle my piss like the great big frilly girls blouse that I am

Moey posted:

The <<<< Computer part was added in once it errored out.

For the code, I need the | measure-object Capacity -sum as if I just do Get-WmiObject Win32_PhysicalMemory, it brings back a table of stuff that I am not interested in.


I feel like this is getting close, I am just missing something stupid.

$mem = (Get-WmiObject Win32_PhysicalMemory | measure-object Capacity -sum).sum/1mb -Computer $ip -Credential $creds -ErrorAction SilentlyContinue | ForEach-Object {$_.Capacity}

So I was wrong about the inadvertent space. With your line of code I was expecting an "unexpected parameter" type error.

Have you tried the line of code from my previous post? I'm about 98% positive it will work for you.

-Computer, -Credentials and -ErrorAction are all parameters of Get-WmiObject so you must provide those before you can pipe to Measure-Object to do your memory calculation.

Adbot
ADBOT LOVES YOU

Moey
Oct 22, 2010

I LIKE TO MOVE IT

Mully Clown posted:


Have you tried the line of code from my previous post? I'm about 98% positive it will work for you.

Yup, you were correct, I am an idiot. I think I missed a chunk of that line you wrote when I copied it. Thanks. Now time to figure out all the other cool things I can add in to this.

Also, suggestions on a good PS book from anyone? I actually found this book in my office, it's almost 5 years old though.

http://www.amazon.com/Microsoft-PowerShell-Programming-Absolute-Beginner/dp/1598633546/ref=sr_1_1?ie=UTF8&qid=1314050807&sr=8-1

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