2011-08-22 19 views
7

Jestem nowy w pisaniu w grze Power Shell, ale to właśnie próbuję osiągnąć.Wyrażenia są dozwolone jako pierwszy element potoku

  1. Chcę porównać daty dwóch plików programu Excel w celu określenia, czy ktoś jest nowszy niż inne.
  2. Chcę przekonwertować plik z CSV na Xls na komputerze, który nie ma programu Excel. Tylko jeśli powyższe stwierdzenie jest prawdziwe, początkowy plik xls został już skopiowany.
  3. Chcę skopiować nowo przekonwertowany plik xls do innej lokalizacji
  4. Jeśli plik jest już otwarty, nie uda się go skopiować, dlatego chcę wysłać wiadomość e-mail z powiadomieniem o powodzeniu lub niepowodzeniu tej operacji.

Oto skrypt, z którym mam problemy. Błąd: "Wyrażenia są dozwolone tylko jako pierwszy element potoku." Wiem, że ma to związek z operacją e-mail, ale nie mam pojęcia, jak to napisać ręcznie z uwzględnieniem wszystkich tych zmiennych. Prawdopodobnie jest więcej błędów, ale nie widzę ich teraz. Dzięki za pomoc, doceniam to!

$CSV = "C:filename.csv" 
$LocalXLS = "C:\filename.xls" 
$RemoteXLS = "D:\filename.xls" 
$LocalDate = (Get-Item $LocalXLS).LASTWRITETIME 
$RemoteDate = (Get-Item $RemoteXLS).LASTWRITETIME 
$convert = "D:\CSV Converter\csvcnv.exe" 
if ($LocalDate -eq $RemoteDate) {break} 
else { 
& $convert $CSV $LocalXLS 
$FromAddress = "[email protected]" 
$ToAddress = "[email protected]" 
$MessageSubject = "vague subject" 
$SendingServer = "mail.mail.com" 
$SMTPMessage = New-Object System.Net.Mail.MailMessage $FromAddress, $ToAddress, $MessageSubject, $MessageBody 
$SMTPClient = New-Object System.Net.Mail.SMTPClient $SendingServer 
$SendEmailSuccess = $MessageBody = "The copy completed successfully!" | New-Object System.Net.Mail.SMTPClient mail.mail.com $SMTPMessage 
$RenamedXLS = {$_.BaseName+(Get-Date -f yyyy-MM-dd)+$_.Extension} 

Rename-Item -path $RemoteXLS -newname $RenamedXLS -force -erroraction silentlycontinue 
If (!$error) 
    { $SendEmailSuccess | copy-item $LocalXLS -destination $RemoteXLS -force } 
Else 
    {$MessageBody = "The copy failed, please make sure the file is closed." | $SMTPClient.Send($SMTPMessage)} 
} 
+2

Nie jestem pewien, co dokładnie próbujesz osiągnąć w tym wierszu: $ SendEmailSuccess = $ MessageBody = "Kopia zakończona pomyślnie!" | New-Object System.Net.Mail.SMTPClient mail.mail.com $ SMTPMessage Ale wyobrażam sobie, że jest winowajcą błędu. – EBGreen

+1

@meep - nie edytuj zawartości. Nie ma sensu mieć wtedy twojego pytania. Przyda się to przyszłym odwiedzającym, nawet jeśli już to wymyśliłeś. Dołącz swoje zmiany. – manojlds

Odpowiedz

4

Błąd ten w zasadzie się dzieje, kiedy użyć wyrażenia po stronie odbiorczej rurociągu, gdy nie można odbierać obiekty z rurociągu.

Można by dostać ten błąd, jeśli coś takiego:

$a="test" | $a 

lub nawet poniżej:

"test" | $a 

nie wiem dlaczego próbują rury wszędzie. Poleciłbym ci poznać podstawy dotyczące potreshell pipelining. Podchodzisz do tego źle. Myślę również, że możesz odnieść się do poniższego linku, aby zobaczyć, jak wysyłać pocztę, powinien być prosty, bez komplikacji, które zostały dodane z rurami: http://www.searchmarked.com/windows/how-to-send-an-email-using-a-windows-powershell-script.php

+2

Uwielbiam fajkę, ale uważam, że jest nadużyta. Zwłaszcza w skryptach. Cały czas używam potoku w wierszu polecenia, ale rzadko używam go w skrypcie. – EBGreen

+2

@EBGreen - Myślę, że prawdziwy problem jest tylko wtedy, gdy naprawdę nie rozumiesz, co się dzieje. Na przykład możesz użyć '$ a | write-host' zamiast 'write-host $ a'. I tak, czasami jest nadużywany. Miło napisać jedno-liniowce, ale trudne do utrzymania skrypty, które inni muszą przeczytać i utrzymać. – manojlds

+2

Yup, nawet jeśli są one używane w scenariuszu całkowicie poprawnie, widzę to jako kwestię dobrych przyzwyczajeń (dla mnie i tak), aby poczynić postępy i uczynić jak najbardziej zrozumiałym w scenariuszu. Oznacza to mniejszą liczbę potoków i wyraźnych nazw poleceń cmdlet niż aliasów. – EBGreen

5

Otrzymujesz ten błąd, gdy próbujesz wykonać niezależne blok kodu z łańcucha potoków.

tylko jako inny przykład wyobrazić, to za pomocą kodu jQuery:

$("div").not(".main").console.log(this) 

Każdy punkt (.) będzie łańcuchowy układ do następnej funkcji. W powyższej funkcji jest to zerwane z console, ponieważ nie ma w nim żadnych wartości. Jeśli chcemy odłączyć się od naszego łączenia, aby wykonać jakiś kod (być może na obiektach w łańcuchu - możemy to zrobić za pomocą each w następujący sposób:

$("div").not(".main").each(function() {console.log(this)}) 

rozwiązaniem jest PowerShell jest identyczna. Jeśli chcesz uruchomić skrypt na każdej pozycji w łańcuchu indywidualnie, można użyć ForEach-Object lub jego alias (%).

Wyobraź sobie następującą funkcję PowerShell:

$settings | ?{$_.Key -eq 'Environment' } | $_.Value = "Prod" 

Ostatnia linia nie może zostać wykonany, ponieważ jest to skrypt, ale we can fix that with ForEach tak:

$settings | ?{$_.Key -eq 'Environment' } | %{ $_.Value = "Prod" } 
Powiązane problemy